Skip to content
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
src
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Erlang Image Manipulation Process

eimp is an Erlang/Elixir application for manipulating graphic images using external C libraries. It supports WebP, JPEG, PNG and GIF.

Requirements

  • GNU Make
  • GCC
  • Erlang/OTP 17 and higher
  • libgd
  • libwebp
  • libpng
  • libjpeg

NOTE: It's hard to say which versions of the C libraries are required, but it seems like not too old versions should work well.

Install

$ ./configure
$ make

Note that running the configure script is highly recommended, so you should consider adding it in pre-hooks of your rebar configuration.

If no C libraries are found at compile time, the package will still be compiled. In this case the only usable function would be get_type/1.

Application design

The C code is compiled into external native binary called eimp, which is connected to Erlang VM using an external port. This is done because used C libraries are known not to be extremely stable, thus, if you wrap them into the emulator using a driver or NIF, they can crash the whole emulator.

When being loaded, the application starts a single eimp process per CPU core and uses a round-robin pool to schedule tasks to them. Simple recovery mechanisms are also supported:

  • if a request to eimp process has failed, next eimp process in the pool is picked, until the pool is exhausted
  • if an eimp process is dead, it will be restarted automatically
  • an eimp process is protected against decompression bombs

Usage

Before using the application you should start it with either eimp:start() or application:start(eimp).

API

Current API is simple and supports only a few functions:

convert/2

-spec convert(In :: binary(), Format :: png|jpeg|webp|gif) -> {ok, Out :: binary()} |
                                                              {error, Reason :: error_reason()}.

Shorthand for convert(In, Format, []).

convert/3

-spec convert(In :: binary(), Format :: png|jpeg|webp|gif,
              Options :: [convert_opt() | limit_opt()]) ->
                   {ok, Out :: binary()} |
                   {error, Reason :: error_reason()}.

The function converts incoming data In into format Format. Note that you don't have to pass the format of incoming data, becasue it will be detected automatically using get_type/1 function. In the case of an error you can use Reason to produce a human-readable diagnostic text using format_error/1. The function also accepts a proplist of Options. Currently available options are:

  • {scale, {Width, Height}}: scales image to the new Width and Height. No scaling is applied by default.
  • {rate_limit, N}: limit the number of calls to N per minute, where N > 0. Must be used only in conjunction with limit_by.
  • {limit_by, Term}: apply rate_limit (see above) to the entity associtated with Term. The Term may represent any value, such as an IP address, a username and so on. The Term must not be atom undefined. For example a call to convert(Data, Format, [{limit_by, {192,168,0,1}}, {rate_limit, 10}]) will fail with {error, too_man_requests} if called more than 10 times within a minute.

WARNING: the maximum resolution of an incoming image is hardcoded to be 25Mpx. This is a protection against decompression bombs.

identify/1

-spec identify(Img :: binary()) -> {ok, Info :: info()} | {error, error_reason()}.

Shorthand for identify(Img, []).

identify/2

-spec identify(Img :: binary(), LimitOptions :: [limit_opt()]) ->
                    {ok, Info :: info()} | {error, error_reason()}.

The function returns information about image Img, where Info is represented as:

[{type, Type :: img_type()},
 {width, Width :: non_neg_integer()},
 {height, Height :: non_neg_integer()}]

It is safe to assume that Info always contains all these properties. You can set limiting options in LimitOptions, that is rate_limit and limit_by. The meaning of the limiting options is the same as in convert/3.

NOTE: If you only need to get a type of an image, you're better off using get_type/1 function, because it doesn't involve interaction with eimp process and is, thus, much faster.

format_error/1

-spec format_error(Reason :: error_reason()) -> binary().

Creates diagnostic text from an error generated by convert/2. The Reason can have the following values:

-type error_reason() :: unsupported_format |
                        timeout |
                        disconnected |
                        encode_failure |
                        decode_failure |
			transform_failure |
			too_many_requests |
			image_too_big.

get_type/1

-spec get_type(Data :: binary()) -> png | jpeg | webp | gif | unknown.

Detects image format of Data.

is_supported/1

-spec is_supported(Format :: atom()) -> boolean.

Returns true if Format is known and compiled and false otherwise.

supported_formats/0

-spec supported_formats() -> [png | jpeg | webp | gif].

Returns a list of all known and compiled formats.

You can’t perform that action at this time.