MagicBytes
Detects MIME types from binary content using magic byte signatures. Only the leading bytes of a file are examined, making detection fast regardless of file size.
Installation
def deps do
[
{:magic_bytes, "~> 0.2"}
]
endUsage
From a file path
MagicBytes.from_path("image.png")
#=> {:ok, "image/png"}
MagicBytes.from_path("archive.tar.gz")
#=> {:ok, "application/gzip"}
MagicBytes.from_path("/nonexistent/file")
#=> {:error, :unreadable}From a binary
Useful when bytes are already in memory — e.g. an upload buffer or a database blob. Only the leading bytes matter; passing the full content works but is not required.
MagicBytes.from_binary(<<0xFF, 0xD8, 0xFF, 0xE0>>)
#=> {:ok, "image/jpeg"}
MagicBytes.from_binary(file_contents)
#=> {:ok, "application/pdf"}
MagicBytes.from_binary(<<0x00, 0x00, 0x00, 0x00>>)
#=> {:error, :unknown}From a stream
Chunks are accumulated until enough bytes are available, then detection runs. The stream is not fully consumed.
File.stream!("video.mkv", 1024)
|> MagicBytes.from_stream()
#=> {:ok, "video/x-matroska"}Guards
For prefix-based signatures a corresponding guard macro is generated and
exported from MagicBytes. Guard names follow the pattern
is_<mime_type> with / and - replaced by _.
require MagicBytes
def process(bin) when MagicBytes.is_image_jpeg(bin), do: ...
def process(bin) when MagicBytes.is_image_png(bin), do: ...
def process(bin) when MagicBytes.is_application_pdf(bin), do: ...
def process(_bin), do: {:error, :unsupported}
Guards also work as boolean expressions outside when clauses:
require MagicBytes
MagicBytes.is_application_gzip(data) #=> true | false
Guards are not generated for container-format signatures where the
distinguishing bytes appear beyond a fixed prefix (WebP, WAV, AVI, AIFF,
MP4, HEIC, AVIF, QuickTime). Use from_binary/1 for those formats.
Custom signatures
Define a module with use MagicBytes.DefineSignatures, configure it once,
and all from_* functions will check your signatures first, falling back to
the built-ins automatically.
defmodule MyApp.Signatures do
use MagicBytes.DefineSignatures, guards: true
# Prefix-based: magic bytes at offset 0
defsignature("application/x-cld", <<0xCA, 0xFE, 0xD0, 0x0D>>)
# Offset-based: magic bytes at a specific byte offset
defsignature_at("application/x-tar", 257, "ustar")
end# config/config.exs
config :magic_bytes,
extra_signatures: MyApp.Signatures,
# Required when using offset-based signatures — set to offset + byte_size(magic)
read_bytes: 262MagicBytes.from_binary(data)
#=> {:ok, "application/x-cld"} # or any built-in type
Passing guards: true generates guard macros on your module for both prefix
and offset signatures. Because your module compiles after the magic_bytes
dependency, guards live on your module rather than on MagicBytes:
require MyApp.Signatures
def process(bin) when MyApp.Signatures.is_application_x_cld(bin), do: ...
def process(bin) when MyApp.Signatures.is_application_x_tar(bin), do: ...ZIP-based formats
Formats that are ZIP files internally (.docx, .xlsx, .odt, etc.) are
correctly detected as application/zip. Distinguishing between them requires
parsing the ZIP structure, which is outside the scope of this library. Pair
with a ZIP parser for sub-format detection if needed.
Configuration
All options are resolved at compile time via Application.compile_env.
| Key | Type | Default | Description |
|---|---|---|---|
:extra_signatures | module | nil |
Module with additional signatures defined via use MagicBytes.DefineSignatures |
:read_bytes | pos_integer | auto | Bytes read from input. Defaults to the minimum required by the built-in signatures. Set explicitly when using offset-based custom signatures. |
:only | list(string) | nil |
When set, only these MIME types are returned; all others become {:error, :unknown} |
:exclude | list(string) | [] |
MIME types to suppress. Ignored when :only is set. |
Supported formats
| Category | MIME types |
|---|---|
| Images | image/jpegimage/pngimage/gifimage/webpimage/bmpimage/tiffimage/x-iconimage/vnd.adobe.photoshopimage/heicimage/avifimage/jp2image/jxlimage/flif |
| Audio | audio/mpegaudio/flacaudio/oggaudio/wavaudio/aiffaudio/mp4 |
| Video | video/mp4video/quicktimevideo/x-matroskavideo/x-flvvideo/x-msvideo |
| Documents | application/pdfapplication/zipapplication/x-cfbapplication/rtf |
| Archives | application/x-rar-compressedapplication/x-7z-compressedapplication/gzipapplication/x-bzip2application/x-xzapplication/zstdapplication/x-lz4 |
| Data | application/vnd.apache.parquetapplication/vnd.apache.arrow.file |
| Executables | application/x-elfapplication/x-msdownloadapplication/x-mach-binaryapplication/wasmapplication/vnd.android.dex |
| Fonts | font/wofffont/woff2font/otffont/ttf |
| Database | application/x-sqlite3 |