{"id":13508368,"url":"https://github.com/Group4Layers/ex_image_info","last_synced_at":"2025-03-30T11:31:44.262Z","repository":{"id":60775469,"uuid":"65488568","full_name":"Group4Layers/ex_image_info","owner":"Group4Layers","description":"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. It is the fastest and supports multiple formats.","archived":false,"fork":false,"pushed_at":"2025-03-06T07:56:30.000Z","size":715,"stargazers_count":98,"open_issues_count":2,"forks_count":5,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-25T00:38:23.916Z","etag":null,"topics":["dimensions","elixir","elixir-lang","elixir-library","image","image-processing","image-recognition","performance","size"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/ex_image_info","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Group4Layers.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-11T17:31:09.000Z","updated_at":"2025-03-16T22:37:53.000Z","dependencies_parsed_at":"2024-06-09T09:27:49.886Z","dependency_job_id":"cc16aab6-07a8-4dce-afad-f2c162d472dc","html_url":"https://github.com/Group4Layers/ex_image_info","commit_stats":{"total_commits":25,"total_committers":2,"mean_commits":12.5,"dds":0.28,"last_synced_commit":"e9627da5990413c291fb66134adf40ac330f9e34"},"previous_names":["rnoz/ex_image_info"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Group4Layers%2Fex_image_info","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Group4Layers%2Fex_image_info/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Group4Layers%2Fex_image_info/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Group4Layers%2Fex_image_info/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Group4Layers","download_url":"https://codeload.github.com/Group4Layers/ex_image_info/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245966908,"owners_count":20701758,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dimensions","elixir","elixir-lang","elixir-library","image","image-processing","image-recognition","performance","size"],"created_at":"2024-08-01T02:00:52.119Z","updated_at":"2025-03-30T11:31:44.249Z","avatar_url":"https://github.com/Group4Layers.png","language":"Elixir","readme":"# README\n\n# ExImageInfo\n\n[![v1.0.0](https://img.shields.io/badge/version-1.0.0-a1c43c.svg)](https://hex.pm/packages/ex_image_info) [![Elixir](https://img.shields.io/badge/made_in-elixir-9900cc.svg)](http://elixir-lang.org) [![Elixir ≥1.13](https://img.shields.io/badge/-≥1.13-9900cc.svg?logo=Elixir)](http://elixir-lang.org) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/Group4Layers/ex_image_info/master/LICENSE.md) [![Coverage](https://img.shields.io/badge/coverage-98.4%25-green.svg)](https://github.com/Group4Layers/ex_image_info) [![Tests](https://img.shields.io/badge/tests-79%2F79-green.svg)](https://github.com/Group4Layers/ex_image_info)\n\nExImageInfo 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. It is the fastest and supports multiple formats.\n\nStatus: [![Elixir 1.18 / OTP 27](https://github.com/Group4Layers/ex_image_info/actions/workflows/build_elixir_latest.yml/badge.svg)](https://github.com/Group4Layers/ex_image_info/actions/workflows/build_elixir_latest.yml) [![Elixir 1.16 / OTP 26](https://github.com/Group4Layers/ex_image_info/actions/workflows/build_elixir_recent.yml/badge.svg)](https://github.com/Group4Layers/ex_image_info/actions/workflows/build_elixir_recent.yml) [![Elixir 1.14 / OTP 25](https://github.com/Group4Layers/ex_image_info/actions/workflows/build_elixir_old.yml/badge.svg)](https://github.com/Group4Layers/ex_image_info/actions/workflows/build_elixir_old.yml) [![Coverage Status](https://coveralls.io/repos/github/Group4Layers/ex_image_info/badge.svg?branch=master)](https://coveralls.io/github/Group4Layers/ex_image_info?branch=master) [![Inline docs](http://inch-ci.org/github/Group4Layers/ex_image_info.svg)](http://inch-ci.org/github/Group4Layers/ex_image_info)\n\n### [GitHub repo](https://github.com/Group4Layers/ex_image_info)  ·  [Docs](https://hexdocs.pm/ex_image_info/ExImageInfo.html)  ·  [Hex.pm package](https://hex.pm/packages/ex_image_info)\n\n## Table of Contents\n\n1. [Description](#description)\n1. [Installation](#installation)\n1. [Examples](#examples)\n1. [Benchmarks](#benchmarks)\n1. [Design decisions](#design-decisions)\n1. [Acknowledgments](#acknowledgments)\n1. [Author](#author)\n1. [Contributors](#contributors)\n1. [ChangeLog](#changelog)\n1. [License](#license)\n\n## Description\n\nMain module that checks and gets if a binary seems to be an image (specific\nformat), the mime-type (and variant detected) and the dimensions of the image\n(based on the type).\n\nIt has convention functions to guess the type of an image by trying the formats\nsupported by the library.\n\n### Main features\n\n- Check the validity of binary by providing a specific image format*.\n- Guess the validity of an image*.\n- Get the mime-type and variant type by providing a specific format.\n- Guess the mime-type and variant type of an image.\n- Get the dimensions of an image by providing a specific format.\n- Guess the dimensions of an image.\n\n*Note: both cases as a general overview (partially checked).\n\n### Formats\n\nSupported formats (image type to be parsed as):\n- `:bmp`\n- `:gif`\n- `:ico`\n- `:jpeg` (`:jpg` alias since `v0.2.3`)\n- `:jp2`\n- `:png`\n- `:pnm`\n- `:psd`\n- `:tiff`\n- `:webp`\n- `:avif`\n- `:heic`\n- `:heif`\n\n## Mime-types and Variants\n\nThe image variant type is an invented string to identify the\ntype of format recognized by this library (more specific than the\nmime-type).\n\nEach mime-type can be linked to at least one variant type:\n\n| mime-type                 | variant type | description        | since version |\n|---------------------------|--------------|--------------------|---------------|\n| `image/avif`              | `AVIF`       |                    | v1.0.0        |\n| `image/avif-sequence`     | `AVIFS`      |                    | v1.0.0        |\n| `image/bmp`               | `BMP`        |                    |               |\n| `image/gif`               | `GIF87a`     | 87a gif spec       |               |\n| `image/gif`               | `GIF89a`     | 89a gif spec       |               |\n| `image/heic`              | `HEIC`       |                    | v1.0.0        |\n| `image/heic-sequence`     | `HEICS`      |                    | v1.0.0        |\n| `image/heif`              | `HEIF`       |                    | v1.0.0        |\n| `image/heif-sequence`     | `HEIFS`      |                    | v1.0.0        |\n| `image/x-icon`            | `ICO`        |                    | v0.2.0        |\n| `image/jp2`               | `JP2`        | JPEG2000           | v0.2.0        |\n| `image/jpeg`              | `baseJPEG`   | baseline JPEG      |               |\n| `image/jpeg`              | `progJPEG`   | progressive JPEG   |               |\n| `image/png`               | `PNG`        |                    |               |\n| `image/x-portable-anymap` | `PNMpbm`     | Portable BitMap    | v0.2.0        |\n| `image/x-portable-anymap` | `PNMpgm`     | Portable GrayMap   | v0.2.0        |\n| `image/x-portable-anymap` | `PNMppm`     | Portable PixMap    | v0.2.0        |\n| `image/psd`               | `PSD`        |                    |               |\n| `image/tiff`              | `TIFFII`     | II variant         |               |\n| `image/tiff`              | `TIFFMM`     | MM variant         |               |\n| `image/webp`              | `webpVP8`    | lossy              |               |\n| `image/webp`              | `webpVP8L`   | lossless           |               |\n| `image/webp`              | `webpVP8X`   | animated           | v0.2.4        |\n\nThe variant type is created just to provide a bit more of information for every image format (if applicable). \nIf version is empty, it means that it was supported since the initial release.\n\nFormats (maybe) containing multiple images:\n- `:ico` returns the dimensions of the largest image found.\n- `:heif`, `:heic` and `:avif` return the dimensions of the main image being selected (`primary_box`).\n\nThe guessing functions try to detect the format of the binary by testing every available type based on its \nglobal usage and current trends (popularity, [usage of image file formats](https://w3techs.com/technologies/overview/image_format/all)):\n- `jpeg`, `png`, `webp`, `avif`, `gif`, `heic`, `heif`, `bmp`, `ico`, `tiff`, `psd`, `jp2`, `pnm`\n\n**Warnings:**\n\n- Use with caution the formats *ico*, *jp2* and the family *pnm*. They are implemented without following \n  other libraries (just reading the specs - sometimes working with old drafts like *jp2*). \n- ISOBMFF format (*heif*, *heic* and *avif*) is the most complex format being supported, with most parts \n  being implemented following the specs and testing against binary streams manually produced.\n  Please, use with caution and report any issue found.\n \n**Contributions:** you can support this library by providing more tests, image *fixtures* (like `image/heic-sequence`),\nincreasing code coverage or extending support for other variants.\n\n\n## Installation\n\nAdd `ex_image_info` to your list of dependencies in `mix.exs`.\n\nFrom Hex:\n\n```elixir\n  def deps do\n    [\n      # ...\n      {:ex_image_info, \"~\u003e 1.0.0\"},\n    ]\n  end\n```\n\nOr GitHub:\n\n```elixir\n  def deps do\n    [\n      # ...\n      {:ex_image_info, github: \"Group4Layers/ex_image_info\"},\n    ]\n  end\n```\n\nThen, use it:\n\n```elixir\nrequire ExImageInfo\n# ExImageInfo.seems? ...\n```\n\n## Examples\n\nThe following examples are run with the latest version of the library under the next environment:\n\n```elixir\nErlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]\n\nInteractive Elixir (1.3.2) - press Ctrl+C to exit (type h() ENTER for help)\niex(1)\u003e\n```\n\n### Feature `seems?`\n\n`89 50 4E 47 0D 0A 1A 0A` are the first 8 bytes in the `PNG` signature (`PNG\\\\r\\\\n0x1A\\\\n`).\n\n```elixir\niex(1)\u003e ExImageInfo.seems? \u003c\u003c0x89504E470D0A1A0A::size(64)\u003e\u003e, :png\ntrue\n\niex(2)\u003e ExImageInfo.seems? \u003c\u003c0x89504E470D0A1A0A::size(64)\u003e\u003e, :webp\nfalse\n```\n\n`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.\n\nUsually it is used as:\n\n```elixir\niex(1)\u003e ExImageInfo.seems? File.read!(\"path/to/image.gif\"), :gif\ntrue\n\niex(2)\u003e maybe_png_binary |\u003e ExImageInfo.seems? :png\nfalse\n```\n\n`38 42 50 53` are the first 4 bytes in the `PSD` signature (`8BPS`).\n\n```elixir\niex(1)\u003e ExImageInfo.seems? \u003c\u003c0x38425053::size(32)\u003e\u003e\n:psd\n\niex(2)\u003e ExImageInfo.seems? \u003c\u003c0x384250::size(24)\u003e\u003e\nnil\n```\n\n`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.\n\nUsually it is used as:\n\n```elixir\niex(1)\u003e ExImageInfo.seems? File.read!(\"path/to/image.unknown\")\n:tiff\n\niex(2)\u003e webp_full_binary |\u003e ExImageInfo.seems?\n:webp\n```\n\n### Feature `type`\n\n`89 50 4E 47 0D 0A 1A 0A` are the first 8 bytes in the `PNG` signature (`PNG\\\\r\\\\n0x1A\\\\n`).\n\n```elixir\niex(1)\u003e ExImageInfo.type \u003c\u003c0x89504E470D0A1A0A::size(64)\u003e\u003e, :png\nnil\n\niex(2)\u003e ExImageInfo.type \u003c\u003c\"RIFF\", 0::size(32), \"WEBPVP8L\", 0::size(32), 0x2F7AC07100358683B68D::size(80)\u003e\u003e, :webp\n{\"image/webp\", \"webpVP8L\"}\n```\n\nThe 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).\n\nUsually it is used as:\n\n```elixir\niex(1)\u003e ExImageInfo.type File.read!(\"path/to/image.gif\"), :gif\n{\"image/gif\", \"GIF87a\"}\n\niex(2)\u003e maybe_png_binary |\u003e ExImageInfo.type :png\nnil\n```\n\nThe *guessed* version.\n\n```elixir\niex(1)\u003e ExImageInfo.type \u003c\u003c0x38425053::size(32)\u003e\u003e\n{\"image/psd\", \"PSD\"}\n\niex(2)\u003e ExImageInfo.type \u003c\u003c0x384250::size(24)\u003e\u003e\nnil\n```\n\nUsually it is used as:\n\n```elixir\niex(1)\u003e ExImageInfo.type File.read!(\"path/to/image.unknown\")\n{\"image/tiff\", \"TIFFMM\"}\n\niex(2)\u003e webp_full_binary |\u003e ExImageInfo.type\n{\"image/webp\", \"webpVP8\"}\n```\n\n### Feature `info`\n\n`89 50 4E 47 0D 0A 1A 0A` are the first 8 bytes in the `PNG` signature (`PNG\\\\r\\\\n0x1A\\\\n`).\n\n```elixir\niex(1)\u003e ExImageInfo.info \u003c\u003c0x89504E470D0A1A0A::size(64)\u003e\u003e, :png\nnil\n\niex(2)\u003e ExImageInfo.info \u003c\u003c\"RIFF\", 0::size(32), \"WEBPVP8L\", 0::size(32), 0x2F7AC07100358683B68D::size(80)\u003e\u003e, :webp\n{\"image/webp\", 123, 456, \"webpVP8L\"}\n```\n\nThe 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).\n\nUsually it is used as:\n\n```elixir\niex(1)\u003e ExImageInfo.info File.read!(\"path/to/image.gif\"), :gif\n{\"image/gif\", 1920, 1080, \"GIF87a\"}\n\niex(2)\u003e maybe_png_binary |\u003e ExImageInfo.info :png\nnil\n```\n\n```elixir\niex(1)\u003e ExImageInfo.info \u003c\u003c0x38425053::size(32)\u003e\u003e\nnil\n\niex(2)\u003e ExImageInfo.info \u003c\u003c0x38425053::size(32), 0::size(80), 10::size(32), 12::size(32)\u003e\u003e\n{\"image/psd\", 12, 10, \"PSD\"}\n```\n\nUsually it is used as:\n\n```elixir\niex(1)\u003e ExImageInfo.info File.read!(\"path/to/image.unknown\")\n{\"image/tiff\", 128, 256, \"TIFFMM\"}\n\niex(2)\u003e webp_full_binary |\u003e ExImageInfo.info\n{\"image/webp\", 20, 100, \"webpVP8\"}\n```\n\n## Benchmarks\n\nGroup4Layers developed the fastest elixir library to obtain the dimensions of the images (binary data parsed). Also, it excels supporting the maximum number of image formats. All without dependencies.\n\n![ExImageInfo Benchmarks](assets/ex_image_info_benchmarks.png)\n\n(The image wouldn't be included in the package).\n\n## Design decisions\n\n### Why `seems?` and not `magic?` or `signature?`?\n\nBecause for some formats it is enough with the [*magic\nnumber*](https://en.wikipedia.org/wiki/Magic_number_(programming)) or the\nsignature to get the type (image format that \"starts\" correctly), but in other\ncases it is an algorithm a bit more complex to see if the binary seems\ncorrect. Therefore, *seems* it is more general (than getting the *magic\nnumber*) and it will provide a \"quick overview\" of the validity of the\nbinary.\n\n### Why returning the mime-type and variant type when getting the dimensions (`info`)?\n\nBecause both types (variant if applicable) are necessary to obtain the width and height\nof the binary for a specific format. In case it is required both the type (and variant) and the dimensions it is not necessary to call two functions (and re-parse part or completely the binary). Therefore, to get the dimensions it is obtained the types and all the information is returned in one step.\n\n### Renamed from ExImageSize to ExImageInfo\n\nAlthough it has been released since the very first version with the name ExImageInfo,\nthis library was previously known as ExImageSize, but it is preferable to have a name\nless restricted. Nowadays it can get information about the type and the dimensions (size),\nbut in a future it could increase the amount of info to extract from an image.\n\n## Acknowledgments\n\nThis idea comes from libraries that I have used in other platforms and/or languages. Algorithms and some concepts are picked and based on parts of the following:\n- image-size (JavaScript) - *Aditya Yadav*\n- imagesize (Ruby) - *Keisuke Minami*\n- fastimage (Ruby) - *Stephen Sykes*\n\nThanks to them.\n\n## Author\n\nnozalr \u003cnozalr@group4layers.com\u003e (Group4Layers®).\n\n## Contributors\n\nSee [CONTRIBUTORS](contributors.html) for more information.\n\n*GitHub readers (repo, no docs): [CONTRIBUTORS.md](CONTRIBUTORS.md).*\n\n## ChangeLog\n\nSee [CHANGELOG](changelog.html) for more information.\n\n*GitHub readers (repo, no docs): [CHANGELOG.md](CHANGELOG.md).*\n\n## License\n\nExImageInfo source code is released under the MIT License.\n\nSee [LICENSE](license.html) for more information.\n\n*GitHub readers (repo, no docs): [LICENSE.md](LICENSE.md).*\n","funding_links":[],"categories":["Images"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGroup4Layers%2Fex_image_info","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGroup4Layers%2Fex_image_info","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGroup4Layers%2Fex_image_info/lists"}