MagicBytes (magic_bytes v0.1.0)

Copy Markdown View Source

Detect MIME types from binary content using magic byte signatures.

Only the first 16 bytes of input are examined. Three entry points cover the common cases — file path, raw binary, and streaming data:

iex> MagicBytes.from_binary(<<0xFF, 0xD8, 0xFF, 0xE0>>)
{:ok, "image/jpeg"}

iex> MagicBytes.from_binary(<<0x00, 0x00, 0x00, 0x00>>)
{:error, :unknown}

Guards

For prefix-based signatures a corresponding guard macro is generated, named is_<mime_with_slashes_and_hyphens_as_underscores>. These expand to pure boolean expressions and can be used in when clauses or regular code after require MagicBytes:

iex> require MagicBytes
iex> MagicBytes.is_image_jpeg(<<0xFF, 0xD8, 0xFF, 0xE0>>)
true

iex> require MagicBytes
iex> MagicBytes.is_application_pdf(<<?%, ?P, ?D, ?F, ?-, ?1, ?., ?7>>)
true

Guards are not generated for container-format signatures that require inspecting bytes beyond a fixed prefix (WebP, WAV, AVI, AIFF, MP4, HEIC, AVIF, QuickTime). Use from_binary/1 for those.

Supported formats

CategoryMIME types

| Images | image/jpeg, image/png, image/gif, image/webp, image/bmp, | image/tiff, image/x-icon, image/vnd.adobe.photoshop, image/heic, image/avif | | Audio | audio/mpeg, audio/flac, audio/ogg, audio/wav, audio/aiff, audio/mp4 | | Video | video/mp4, video/quicktime, video/x-matroska, video/x-flv, video/x-msvideo | | Documents | application/pdf, application/zip, application/x-cfb, application/rtf | | Archives | application/x-rar-compressed, application/x-7z-compressed, application/gzip, | | application/x-bzip2, application/x-xz, application/zstd | | Executable | application/x-elf, application/x-msdownload, application/x-mach-binary, application/wasm | | Fonts | font/woff, font/woff2, font/otf, font/ttf | | Database | application/x-sqlite3 |

Summary

Types

error()

@type error() :: {:error, :unreadable | :unknown}

mime_type()

@type mime_type() :: String.t()

Functions

from_binary(data)

@spec from_binary(binary()) :: {:ok, mime_type()} | error()

Detects the MIME type from a binary.

Only the first 16 bytes are examined; passing the full file content is fine but unnecessary.

Examples

iex> MagicBytes.from_binary(<<0xFF, 0xD8, 0xFF, 0xE0>>)
{:ok, "image/jpeg"}

iex> MagicBytes.from_binary(<<0x89, "PNG", 0x0D, 0x0A, 0x1A, 0x0A>>)
{:ok, "image/png"}

iex> MagicBytes.from_binary(<<?%, ?P, ?D, ?F>>)
{:ok, "application/pdf"}

iex> MagicBytes.from_binary(<<0x1F, 0x8B>>)
{:ok, "application/gzip"}

iex> MagicBytes.from_binary(<<0x00, 0x00, 0x00, 0x00>>)
{:error, :unknown}

from_path(path)

@spec from_path(Path.t()) :: {:ok, mime_type()} | error()

Detects the MIME type of the file at path by reading its first 16 bytes.

Returns {:error, :unreadable} if the file cannot be opened.

Examples

iex> MagicBytes.from_binary("image_file.jpg")
iex> {:ok, "image/jpg"}

iex> MagicBytes.from_binary("pdf_file.pdf")
iex> {:ok, "application/pdf"}

iex> MagicBytes.from_path("/nonexistent/file.jpg")
{:error, :unreadable}

from_stream(stream)

@spec from_stream(Enumerable.t()) :: {:ok, mime_type()} | error()

Detects the MIME type from a stream of binaries.

Chunks are accumulated until at least 16 bytes are available, then detection runs on the combined header. The stream is not fully consumed.

Returns {:error, :unreadable} if the stream is empty.

Examples

iex> MagicBytes.from_stream([<<0xFF, 0xD8, 0xFF, 0xE0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>])
{:ok, "image/jpeg"}

iex> MagicBytes.from_stream([<<0xFF, 0xD8>>, <<0xFF, 0xE0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>>])
{:ok, "image/jpeg"}

iex> MagicBytes.from_stream([])
{:error, :unreadable}

is_application_gzip(bin)

(macro)

is_application_pdf(bin)

(macro)

is_application_rtf(bin)

(macro)

is_application_wasm(bin)

(macro)

is_application_x_7z_compressed(bin)

(macro)

is_application_x_bzip2(bin)

(macro)

is_application_x_cfb(bin)

(macro)

is_application_x_elf(bin)

(macro)

is_application_x_mach_binary(bin)

(macro)

is_application_x_msdownload(bin)

(macro)

is_application_x_rar_compressed(bin)

(macro)

is_application_x_sqlite3(bin)

(macro)

is_application_x_xz(bin)

(macro)

is_application_zip(bin)

(macro)

is_application_zstd(bin)

(macro)

is_audio_flac(bin)

(macro)

is_audio_mpeg(bin)

(macro)

is_audio_ogg(bin)

(macro)

is_font_otf(bin)

(macro)

is_font_ttf(bin)

(macro)

is_font_woff2(bin)

(macro)

is_font_woff(bin)

(macro)

is_image_bmp(bin)

(macro)

is_image_gif(bin)

(macro)

is_image_jpeg(bin)

(macro)

is_image_png(bin)

(macro)

is_image_tiff(bin)

(macro)

is_image_vnd_adobe_photoshop(bin)

(macro)

is_image_x_icon(bin)

(macro)

is_video_x_flv(bin)

(macro)

is_video_x_matroska(bin)

(macro)