ExImageInfo (ExImageInfo v1.0.0)

View Source

ExImageInfo is an Elixir library to parse images (binaries) and get the dimensions (size), detected mime-type and overall validity for a set of image formats. Main module to parse a binary and get if it seems to be an image (validity), the mime-type (and variant detected) and the dimensions of the image, based on a specific image format.

It has convention functions to guess the type of an image by trying the formats supported by the library.

Main features

  • Check the validity of binary by providing a specific image format*.
  • Guess the validity of an image*.
  • Get the mime-type and variant type by providing a specific format.
  • Guess the mime-type and variant type of an image.
  • Get the dimensions of an image by providing a specific format.
  • Guess the dimensions of an image.

*Note: both cases as a general overview (partially checked).

Formats

Supported formats (image type to be parsed as):

  • :bmp
  • :gif
  • :ico
  • :jpeg (:jpg alias since v0.2.3)
  • :jp2
  • :png
  • :pnm
  • :psd
  • :tiff
  • :webp
  • :avif
  • :heic
  • :heif

Mime-types and Variants

The image variant type is an invented string to identify the type of format recognized by this library (more specific than the mime-type).

Each mime-type can be linked to at least one variant type:

mime-typevariant typedescriptionsince version
image/avifAVIFv1.0.0
image/avif-sequenceAVIFSv1.0.0
image/bmpBMP
image/gifGIF87a87a gif spec
image/gifGIF89a89a gif spec
image/heicHEICv1.0.0
image/heic-sequenceHEICSv1.0.0
image/heifHEIFv1.0.0
image/heif-sequenceHEIFSv1.0.0
image/x-iconICOv0.2.0
image/jp2JP2JPEG2000v0.2.0
image/jpegbaseJPEGbaseline JPEG
image/jpegprogJPEGprogressive JPEG
image/pngPNG
image/x-portable-anymapPNMpbmPortable BitMapv0.2.0
image/x-portable-anymapPNMpgmPortable GrayMapv0.2.0
image/x-portable-anymapPNMppmPortable PixMapv0.2.0
image/psdPSD
image/tiffTIFFIIII variant
image/tiffTIFFMMMM variant
image/webpwebpVP8lossy
image/webpwebpVP8Llossless
image/webpwebpVP8Xanimatedv0.2.4

The variant type is created just to provide a bit more of information for every image format (if applicable). If version is empty, it means that it was supported since the initial release.

Formats (maybe) containing multiple images:

  • :ico returns the dimensions of the largest image found.
  • :heif, :heic and :avif return the dimensions of the main image being selected (primary_box).

The guessing functions try to detect the format of the binary by testing every available type based on its global usage and current trends (popularity, usage of image file formats):

  • jpeg, png, webp, avif, gif, heic, heif, bmp, ico, tiff, psd, jp2, pnm

Warnings:

  • Use with caution the formats ico, jp2 and the family pnm. They are implemented without following other libraries (just reading the specs - sometimes working with old drafts like jp2).
  • ISOBMFF format (heif, heic and avif) is the most complex format being supported, with most parts being implemented following the specs and testing against binary streams manually produced. Please, use with caution and report any issue found.

Contributions: you can support this library by providing more tests, image fixtures (like image/heic-sequence), increasing code coverage or extending support for other variants.

Summary

Types

Supported image format types.

Functions

Gets the mime-type, variant-type and dimensions (width, height) for the given image binary (guessed version of ExImageInfo.info/2).

Gets the mime-type, variant-type and dimensions (width, height) for the given image format and binary.

Detects the image format that seems to be the given binary (guessed version of ExImageInfo.seems?/2).

Detects if the given binary seems to be in the given image format.

Gets the mime-type and variant type for the given image binary (guessed version of ExImageInfo.type/2).

Gets the mime-type and variant type for the given image format and binary.

Types

image_format()

@type image_format() ::
  :jpeg
  | :jpg
  | :png
  | :webp
  | :avif
  | :gif
  | :heic
  | :heif
  | :bmp
  | :ico
  | :tiff
  | :psd
  | :jp2
  | :pnm

Supported image format types.

Functions

info(binary)

@spec info(binary()) ::
  {mimetype :: String.t(), width :: integer(), height :: integer(),
   variant :: String.t()}
  | nil

Gets the mime-type, variant-type and dimensions (width, height) for the given image binary (guessed version of ExImageInfo.info/2).

Possible Mime-types and Variants to be returned.

Returns a 4-item tuple with the mime-type, width, height and the variant type when the binary matches, nil otherwise.

Examples

iex> ExImageInfo.info <<0x38425053::size(32)>>
nil
iex> ExImageInfo.info <<0x38425053::size(32), 0::size(80), 10::size(32), 12::size(32)>>
{"image/psd", 12, 10, "PSD"}

Usually it is used as:

ExImageInfo.info File.read!("path/to/image.unknown")
# {"image/tiff", 128, 256, "TIFFMM"}

webp_full_binary |> ExImageInfo.info
# {"image/webp", 20, 100, "webpVP8"}

info(binary, format)

@spec info(binary(), format :: image_format()) ::
  {mimetype :: String.t(), width :: integer(), height :: integer(),
   variant :: String.t()}
  | nil

Gets the mime-type, variant-type and dimensions (width, height) for the given image format and binary.

Possible Mime-types and Variants to be returned.

Valid formats to be used.

Returns a 4-item tuple with the mime-type, width, height and the variant type when the binary matches, nil otherwise.

Examples

89 50 4E 47 0D 0A 1A 0A are the first 8 bytes in the PNG signature (PNG\r\n0x1A\n).

iex> ExImageInfo.info <<0x89504E470D0A1A0A::size(64)>>, :png
nil
iex> ExImageInfo.info <<"RIFF", 0::size(32), "WEBPVP8L", 0::size(32), 0x2F7AC07100358683B68D::size(80)>>, :webp
{"image/webp", 123, 456, "webpVP8L"}

The signature part of a png it is now enough to get the type (it check also the IHDR field, just before the width and height).

Usually it is used as:

ExImageInfo.info File.read!("path/to/image.gif"), :gif
# {"image/gif", 1920, 1080, "GIF87a"}

maybe_png_binary |> ExImageInfo.info :png
# nil

If a binary is malformed, it returns nil, even if other calls like type or seems? return valid types.

{ExImageInfo.type(malformed_heif_binary, :heif), ExImageInfo.info(malformed_heif_binary, :heif)}
# {{"image/heif", "HEIF"}, nil}

seems?(binary)

@spec seems?(binary()) :: image_format() | nil

Detects the image format that seems to be the given binary (guessed version of ExImageInfo.seems?/2).

Returns the valid format (atom) if it matches, nil otherwise.

Examples

38 42 50 53 are the first 4 bytes in the PSD signature (8BPS).

iex> ExImageInfo.seems? <<0x38425053::size(32)>>
:psd
iex> ExImageInfo.seems? <<0x384250::size(24)>>
nil

ExImageInfo.seems?/2 and ExImageInfo.seems?/1 does not necessarily needs a real image (as it is shown in the previous example) because it just checks the signature of every file format.

Usually it is used as:

ExImageInfo.seems? File.read!("path/to/image.unknown")
# :tiff

webp_full_binary |> ExImageInfo.seems?
# :webp

seems?(binary, format)

@spec seems?(binary(), format :: image_format()) :: boolean()

Detects if the given binary seems to be in the given image format.

Valid formats to be used.

Returns true if the binary seems to be the format specified, false if it is not, and nil if the type is unsupported.

Examples

89 50 4E 47 0D 0A 1A 0A are the first 8 bytes in the PNG signature (PNG\r\n0x1A\n).

iex> ExImageInfo.seems? <<0x89504E470D0A1A0A::size(64)>>, :png
true
iex> ExImageInfo.seems? <<0x89504E470D0A1A0A::size(64)>>, :webp
false

ExImageInfo.seems?/2 and ExImageInfo.seems?/1 does not necessarily needs a real image (as it is shown in the previous example) because it just checks the signature of every file format.

Usually it is used as:

ExImageInfo.seems? File.read!("path/to/image.gif"), :gif
# true

maybe_png_binary |> ExImageInfo.seems? :png
# false

type(binary)

@spec type(binary()) :: {mimetype :: String.t(), variant :: String.t()} | nil

Gets the mime-type and variant type for the given image binary (guessed version of ExImageInfo.type/2).

Possible Mime-types and Variants to be returned.

Returns a 2-item tuple with the mime-type and the variant type when the binary matches, nil otherwise.

Examples

iex> ExImageInfo.type <<0x38425053::size(32)>>
{"image/psd", "PSD"}
iex> ExImageInfo.type <<0x384250::size(24)>>
nil

Usually it is used as:

ExImageInfo.type File.read!("path/to/image.unknown")
# {"image/tiff", "TIFFMM"}

webp_full_binary |> ExImageInfo.type
# {"image/webp", "webpVP8"}

type(binary, format)

@spec type(binary(), format :: image_format()) ::
  {mimetype :: String.t(), variant :: String.t()} | nil

Gets the mime-type and variant type for the given image format and binary.

Possible Mime-types and Variants to be returned.

Valid formats to be used.

Returns a 2-item tuple with the mime-type and the variant type when the binary matches, nil otherwise.

Examples

89 50 4E 47 0D 0A 1A 0A are the first 8 bytes in the PNG signature (PNG\r\n0x1A\n).

iex> ExImageInfo.type <<0x89504E470D0A1A0A::size(64)>>, :png
nil
iex> ExImageInfo.type <<"RIFF", 0::size(32), "WEBPVP8L", 0::size(32), 0x2F7AC07100358683B68D::size(80)>>, :webp
{"image/webp", "webpVP8L"}

The signature part of a png it is now enough to get the type (it check also the IHDR field, just before the width and height).

Usually it is used as:

ExImageInfo.type File.read!("path/to/image.gif"), :gif
# {"image/gif", "GIF87a"}

maybe_png_binary |> ExImageInfo.type :png
# nil