Processes images in your own code, and holds the configuration that
ImagePipe.Plug serves images with.
builder =
ImagePipe.URL.new()
|> ImagePipe.URL.group(resize: [width: 400, height: 300, fit: :cover])
|> ImagePipe.URL.output(format: :webp)
{:ok, result} = ImagePipe.run(ImagePipe.config(), builder, {:file, "cat.jpg"})config/1 builds a configuration, ImagePipe.URL describes what to do to
the image, and run/4 returns the result. write/5 writes it to a file
instead. Processing images in Elixir walks
through it.
An instance is a supervised process that holds a configuration and starts
the processes its caches need. Run one with child_spec/1 when a mount's
configuration reads runtime values, such as environment variables, or when
the configuration uses a bounded cache. ImagePipe.Plug mounts, run/4,
write/5, validate/2, and url_config/2 find it by name.
Summary
Functions
Returns a child specification that runs a named ImagePipe instance.
Builds the configuration that ImagePipe.Plug mounts, instances, and
run/4 use.
Runs a builder's plan on an image and returns the encoded result.
Returns the URL settings a configuration or a running instance serves, for
building URLs with ImagePipe.URL.new/1.
Checks a builder's plan as this configuration would serve it.
Runs a builder's plan like run/4, then writes the result to path.
Functions
@spec child_spec(keyword()) :: Supervisor.child_spec()
Returns a child specification that runs a named ImagePipe instance.
Start the instance in your application's supervision tree, before the endpoint that mounts it. Its options are evaluated when the application starts, so they can read environment variables:
children = [
{ImagePipe,
name: MyApp.Images,
sources: [...],
cache:
{ImagePipe.Cache.FileSystem,
root: "/var/cache/image_pipe/processed",
max_size_bytes: 5_000_000_000,
node_id: "node-0"}},
MyAppWeb.Endpoint
]Mount it with the :instance option of ImagePipe.Plug, and pass its name
to run/4, write/5, validate/2, and url_config/2.
A bounded ImagePipe.Cache.FileSystem runs processes that track the
cache's size, and only an instance starts them. A configuration with such a
cache must be used through an instance. An inline ImagePipe.Plug mount,
and run/4 with a configuration from config/1, raise ArgumentError for
it. Setting one up is covered in
Caching processed images.
Options
:name(atom/0) - Required. Name thatImagePipe.Plugmounts,ImagePipe.run/4,ImagePipe.write/5,ImagePipe.validate/2, andImagePipe.url_config/2use to find the instance. It also names the instance's supervisor.:mounts(keyword/0) - Named sets of URL options, such as[signed: [keys: [key]]]. AnImagePipe.Plugmount picks one with its:mountoption, so mounts with different signing keys share one instance and its caches. Each set takes the URL options ofImagePipe.config/1(:base_url,:keys,:encrypt_source,:source_encryption_keys,:iv_mode) and applies them on top of the instance's own, so an option a set leaves out keeps the instance's value. For a mount that doesn't check signatures, setkeys: [], andsource_encryption_keys: []if the instance has them. The default value is[].:config(ImagePipe.Config.t/0) - A configuration fromImagePipe.config/1to start from. The other options override it.:detector_warmup(:all,false, or a list of class names) - Which detector classes to load models for when the instance starts, usingImagePipe.Transform.Detector.Warmup.:allloads every model, a list such as["face"]loads only the models those classes need, andfalseloads none. Nothing is loaded when the configuration's detector isn't available. A class the detector doesn't support raisesArgumentError. The default value is:all.
Every option of config/1 is accepted too. Invalid options raise
ArgumentError when the child specification is built, before the
instance starts.
@spec config(keyword()) :: ImagePipe.Config.t()
Builds the configuration that ImagePipe.Plug mounts, instances, and
run/4 use.
config =
ImagePipe.config(
sources: [
media: [
adapter: ImagePipe.Source.File,
match: :path,
options: [root: "/srv/images", root_id: "media"]
]
],
presets: %{"card" => "w=400/h=300/fit=cover"},
quality: 82
)Invalid options raise ArgumentError, without credentials in the message.
Building a configuration reads no sources or caches. Inspecting one hides its
values.
Elixir configuration shows which settings belong here and which belong to a mount, a source, or a request.
keys and source_encryption_keys set which URLs an ImagePipe.Plug
mount accepts. base_url, encrypt_source, and iv_mode only affect URLs
built from the configuration with url_config/2.
Options
:base_url(String.t/0) - Prefix for generated URLs: an HTTP(S) URL such as"https://cdn.example.com/images", a root-relative path such as"/images", or a relative path such as"images". A trailing/is removed. Path segments use unescaped ASCII letters, digits,-,.,_, or~. A base URL with credentials, a query string, a fragment, an empty segment, or a.or..segment raises. With the default, URLs start with/, such as/w=400/src/cat.jpg. The default value is"".:keys(list of hex-encodedString.t/0) - Signing keys, each at least 64 hex digits (32 bytes), such as the output ofopenssl rand -hex 32. A shorter key raisesArgumentError. The first key signs generated URLs. The server accepts a signature from any key in the list, so keep an old key while URLs signed with it are in use. Without keys, URLs are unsigned and the server rejects signed ones. The default value is[].:encrypt_source(boolean/0) - Encrypts the source, and any watermark source, in generated URLs, which then useenc/<token>instead ofsrc/<path>. Requires:source_encryption_keys. A server with encryption keys decryptsenc/sources regardless of this option. The default value isfalse.:source_encryption_keys(list of hex-encodedString.t/0) - Keys that encrypt and decrypt sources, each 32 bytes written as 64 hex digits in either case, such as the output ofopenssl rand -hex 32. The first key encrypts. The server decrypts with any key in the list. The keys must differ from the signing keys, and setting them requires:keys. The default value is[].:iv_mode(:deterministicor:random) - HowImagePipe.URL.url/3picks the initialization vector for an encrypted source.:deterministicderives it from the source with a secret key, so one source always gives the same URL.:randomgives a new URL on every call. The default value is:deterministic.:sources(keyword/0) - Named sources that originals are read from, asname: [adapter: module, match: rule, options: [...]]. See sources.:source_cache_policy(keyword/0) - Default cache storage and freshness policy for every source. SeeImagePipe.Source.CachePolicyand source cache settings.:max_body_bytes(pos_integer/0) - Maximum size of an original, in bytes. A larger original fails the request. The default value is10000000.:max_input_pixels(pos_integer/0) - Maximum pixels of a decoded original. For an animation, counts the frames composited to reach the requestedpage. A larger original fails the request. The default value is40000000.:max_input_frames(pos_integer/0) - Maximum frames or pages an original may declare. An original with more fails the request. The default value is1000.:max_result_width(pos_integer/0) - Maximum output width. Larger results are scaled down to fit. The default value is8192.:max_intermediate_pixels(pos_integer/0) - Maximum pixels in a decoded frame buffered, downsampled, or delivered during processing. Larger frames fail with422. Lazy intermediate frames may be larger when a crop reduces them before those steps. The default value is100000000.:max_result_height(pos_integer/0) - Maximum output height. Larger results are scaled down to fit. The default value is8192.:max_result_pixels(pos_integer/0) - Maximum output pixels. Larger results are scaled down to fit. The default value is40000000.:processing_pool(atom/0orpid/0) - A runningImagePipe.ProcessingPool, by name or PID, that limits how many images are processed at once. See limiting concurrent processing.:auto_avif(boolean/0) - Serve AVIF when the request'sAcceptheader lists it. The default value istrue.:auto_webp(boolean/0) - Serve WebP when the request'sAcceptheader lists it. The default value istrue.:format_order(list of:avifand:webp) - Which format wins whenAcceptlists both. A format left out of the list comes after the listed ones. The default value is[:avif, :webp].:quality(pos_integer/0) - Encoder quality,1..100, for formats without a:format_quality. The default value is80.:format_quality(map ofatom/0keys andpos_integer/0values) - Quality per output format,1..100. Merged with the defaults,%{webp: 79, avif: 63}. A request'sqreplaces this table, and itsformat-qreplaces the entries for the formats it lists. Seeformat-q.:strip_metadata(boolean/0) - Remove EXIF, XMP, and other optional metadata from the output. The default value istrue.:keep_copyright(boolean/0) - Keep copyright and artist fields when stripping metadata. The default value istrue.:stripped_dpi(pos_integer/0) - Density written to the output,1..65535, when metadata is stripped and the request has nodpi. The default value is72.:strip_color_profile(boolean/0) - Convert the output to sRGB (or gray) and leave out the original's ICC profile.falsekeeps the original's profile. The default value istrue.:preserve_hdr(boolean/0) - Keep high bit depth in output formats that support it. The default value isfalse.:skip_processing_formats(list ofatom/0) - Original formats, such as[:gif], served unchanged instead of processed when the request names no otherformatand draws no watermark. The unchanged original keeps its metadata, including any location data, and only:max_body_byteslimits it. See formats. The default value is[].:autoquality(boolean/0) - Picks each image's quality to meet:autoquality_targetby encoding and scoring several qualities. A request can turn it on or off and set its own target withautoquality. The default value isfalse.:autoquality_target- The SSIMULACRA2 score auto-quality aims for, above0and up to100. The default value is75.:jpeg_options(keyword/0) - Default JPEG encoder settings, as a keyword list with the fields of thejpeg_options:option ofImagePipe.URL.output/2, such as[interlace: true]. A request's settings win field by field. See encoder options and the builder names in URL option names.:png_options(keyword/0) - Default PNG encoder settings, as for:jpeg_options.:webp_options(keyword/0) - Default WebP encoder settings, as for:jpeg_options.:effortdefaults to4.:avif_options(keyword/0) - Default AVIF encoder settings, as for:jpeg_options.:effortdefaults to3and:subsample_modeto:off.:detector(:default,nil, ormodule/0) - The detector for face and object detection.:defaultuses the built-in detector when its dependencies are installed,nilturns detection off, and a module uses a custom detector. See enabling detection. The default value is:default.:detector_required(boolean/0) - Fail requests that ask for detection when it can't run:501when the detector can't detect the requested classes in this build,503when its models aren't downloaded, and500when detection fails. Withfalse, the crop falls back to attention cropping.anchor=smart-facealways falls back. Withtrue,ImagePipe.config/1raisesArgumentErrorwhen the detector can't detect any class. The default value isfalse.:telemetry_prefix(list ofatom/0) - Prefix of every telemetry event name. See telemetry. The default value is[:image_pipe].:clock((-> integer())) - Returns the current Unix time in seconds, for checking a URL'sexpires. The system clock by default.:cache({module, keyword}) - Cache for processed images, such as{ImagePipe.Cache.FileSystem, root: "/var/cache/image_pipe/processed"}. See caching processed images. Off by default.:input_cache({module, keyword}) - Cache for originals fetched from sources, configured like:cache. See originals cache. Off by default.:storage_inputs(list of{:header, name}or{:cookie, name}) - Request headers and cookies whose values select separate cached copies, such as[{:header, "x-tenant"}]. They aren't sent to the source and don't change the image. The default value is[].:watermarks(map ofatom/0tokeyword/0) - Named watermark images that requests select withwm=name, as%{logo: [source: "brand/logo.png", opacity: 0.6]}. Names match[a-z0-9_-]+.:sourceis an image path that a configured source serves.:opacity, above0and at most1, defaults to1and multiplies the request'swm-opacity. See watermarks. The default value is%{}.:request_watermarks(boolean/0) - Let requests overlay any image the configured sources serve, withwm-src64orwm-enc, besides the named:watermarks. The default value isfalse.:presets(map ofString.t/0to fragment orImagePipe.URLbuilder) - Named sets of options that URLs select withpreset=name, as URL fragments such as%{"card" => "w=400/h=300/fit=cover"}orImagePipe.URLbuilders. See defining presets. The default value is%{}.:request_defaults(fragment orImagePipe.URLbuilder) - Options applied to the first group of every request, before presets and the request's own options. One group, with nopreset.:preset_lookup({module, keyword}) - Looks up preset names that:presetsdoesn't define, per request. SeeImagePipe.PresetLookupand storing presets in a database.:max_preset_lookups(pos_integer/0) - Most distinct names one request may look up. Only with:preset_lookup. The default value is32.
@spec run( ImagePipe.Config.t() | atom(), ImagePipe.URL.t(), {:file | :binary | :source, binary()}, keyword() ) :: {:ok, ImagePipe.Result.t()} | {:error, term()}
Runs a builder's plan on an image and returns the encoded result.
builder =
ImagePipe.URL.new()
|> ImagePipe.URL.group(resize: [width: 400])
|> ImagePipe.URL.output(format: :webp)
{:ok, result} = ImagePipe.run(ImagePipe.config(), builder, {:file, "photos/cat.jpg"})
result.content_type
#=> "image/webp"config comes from config/1, or is the name of a running instance. A
configuration with a bounded cache must be passed by its instance's name.
Presets and request defaults come from config, as for a request to an
ImagePipe.Plug mount. The builder's own URL configuration isn't used.
Matching source bytes, plans, settings, and Accept preferences give the
same result as an HTTP request.
Inputs
{:source, source}- a source the configuration's configured sources resolve, as for an HTTP request: a path, an HTTP(S) URL such as"https://assets.example.com/cat.jpg", an S3 identifier, or a custom scheme. Pass the source without thesrc/marker or the URL escaping of the request path. The source's network, redirect, timeout, and content-type policies apply. These inputs use the configuration's caches, sorun/4and HTTP requests reuse each other's stored copies when the plan,Acceptpreferences, and request inputs match.{:file, path}- a local file, by absolute path or relative to the current working directory. Symlinks are followed, and the path must end at a regular file. The path isn't confined to a directory. Use a{:source, path}with anImagePipe.Source.Filesource for that.{:binary, bytes}- an encoded image in memory, such as an upload.
{:file, path} and {:binary, bytes} inputs are never cached. Every input
is subject to :max_body_bytes, :max_input_pixels, and
:max_input_frames.
Options
Every option of config/1 overrides the configuration for this call, such
as max_input_pixels: 50_000_000. Invalid options raise ArgumentError.
An instance name takes the same options, but a bounded :cache or
:input_cache raises ArgumentError unless it is one of the instance's
own caches. run/4 and write/5 also take:
:accept(String.t/0) - An HTTPAcceptvalue, such as"image/avif,image/webp", for choosing the output format when the plan has noformat. An empty value keeps the original's format where possible, as for a request withoutAccept(see output formats).:auto_avif,:auto_webp, and:format_orderapply as configured. The default value is"".:request_inputs(keyword/0) - The header and cookie values named by the configuration's:storage_inputs, for{:source, source}inputs. They select the same stored copy as those values in an HTTP request. Header names are case-insensitive, and cookie names are case-sensitive. A missing value matches a request without it. They aren't sent to the source and don't change the result. The default value is[].:headers(list of{String.t(), String.t()}) - Header values, such as[{"x-tenant", "one"}]. Names must be valid header names, and values can't contain control characters. The default value is[].:cookies(map ofString.t/0toString.t/0) - Cookie values by name, such as%{"session" => "abc"}. The default value is%{}.
The builder's request controls behave as in a URL. cachebuster selects a
separate stored copy. expires is compared with the configuration's
:clock, and a plan is still valid at its exact expires second.
filename, attachment, and debug don't change the result.
Options that have no effect, such as fit: :cover without a width or
height, are ignored. The [:request, :ignored_options]
telemetry event reports the
ones the builder sets.
Return values
Returns {:ok, %ImagePipe.Result{}}, or {:error, reason}:
{:invalid_request, issues}- an option is unknown or has an invalid value, the builder's options don't combine, or it names an unknown preset or watermark.issuesis a list ofImagePipe.Plan.Spec.Issue.:expired- the plan'sexpirestime has passed.{:invalid_output, reason}- the output options can't be combined, such ascolor_profile: {:convert, :srgb}withhdr: :preserve. A configured default counts too.{:unsupported_output_format, format}- no encoder for the format.{:detector, reason}- detection is required andreasonis:unavailableor:not_ready, or the plan names detection classes the detector lacks ({:unknown_classes, names}).{:preset, reason}- the configuration's preset lookup failed::too_many_presetswhen the plan names more presets to look up than:max_preset_lookupsallows,:lookup_unavailable, or:invalid_definition.{:invalid_source, reason}- the input isn't one of the tuples above, the source isn't valid UTF-8, or the source or awatermark_sourcein the plan can't be parsed.{:source, reason}- the source or a watermark source couldn't be read, such as{:source, :enoent}for a missing file,{:source, :not_found}for a path no configured source matches, or{:source, :body_too_large}.{:input_limit, reason}- the decoded image exceeds:max_input_pixelsor:max_input_frames.{:page_out_of_range, page, pages}- the builder'spagedoesn't exist in the original.{:decode, reason}- the input isn't an image ImagePipe can decode.{:transform, reason}- processing failed, such as aregionoutside the image.{:encode, reason}or{:encode, exception, stacktrace}- encoding failed.{:processing, reason}- the processing pool rejected or stopped the work, such as:overloaded,:queue_timeout, or:timeout.
The checks that don't need the image run first, so {:invalid_request, _},
:expired, {:invalid_output, _}, {:unsupported_output_format, _},
{:detector, _}, and {:preset, _} return before any source is read. Errors raised by
transform code propagate.
Resources
The result is complete when run/4 returns, and holds no open file,
source, or image. Source resources are closed before run/4 returns, on
success and on failure. The result is held in memory, so running large
outputs concurrently needs memory for each complete result.
@spec url_config(ImagePipe.Config.t() | atom(), keyword()) :: ImagePipe.URL.Config.t()
Returns the URL settings a configuration or a running instance serves, for
building URLs with ImagePipe.URL.new/1.
MyApp.Images
|> ImagePipe.url_config()
|> ImagePipe.URL.new()
|> ImagePipe.URL.group(resize: [width: 400])
|> ImagePipe.URL.url!("images/cat.jpg")The result carries the configuration's presets, request defaults, and
watermark settings as its :validate_against option, so
ImagePipe.URL.validate/1 and ImagePipe.URL.url/3 check plans against
them.
Options
:mount(atom/0) - One of the instance's:mounts, whose URL options the result uses instead of the instance's own.
Raises ArgumentError for an invalid option, when no instance with the
name is running or it has no mount with that name, or when :mount comes
with a configuration.
@spec validate(ImagePipe.Config.t() | atom(), ImagePipe.URL.t()) :: {:ok, [ImagePipe.Plan.Spec.Issue.t()]} | {:error, term()}
Checks a builder's plan as this configuration would serve it.
Applies request defaults and presets, including the preset lookup, then
checks the request, its output policy, and its watermark sources. Returns
{:ok, warnings}, the ImagePipe.Plan.Spec.Issue warnings for options
run/4 would ignore and for mistakes the builder repaired, or the error
run/4 would return, without reading a source or accessing a cache.
@spec write( ImagePipe.Config.t() | atom(), ImagePipe.URL.t(), {:file | :binary | :source, binary()}, Path.t(), keyword() ) :: {:ok, ImagePipe.Result.t()} | {:error, term()}
Runs a builder's plan like run/4, then writes the result to path.
{:ok, result} =
ImagePipe.write(ImagePipe.config(), builder, {:binary, upload}, "thumbs/cat.webp")Takes the same inputs and options, and returns the same result, as
run/4. The file holds result.data, with an :info result written as
JSON. An existing file is overwritten.
The output format comes from the plan or from :accept, never from the
file name, so "cat.jpg" can hold WebP. Set format: with
ImagePipe.URL.output/2 to match the file name.
Returns run/4's errors, or {:error, {:destination, reason}} when the
file can't be written, such as {:destination, :enoent} for a missing
directory. The file is written after source resources are closed.