Releases: elixir-image/image
Release list
Image version 0.71.0
Added
-
Adds
### Examplesdoctest sections to more than 220 public functions acrossImageand its submodules. All examples run as doctests. -
Adds a
rangeargument (:limitedor:full) to theImage.YUVencode and decode functions, andImage.YUV.valid_ranges/0.:limited(studio-swing) is the default and matches the previous behaviour.
Fixed
- Fix
Image.YUVto use studio-swing (limited range) coefficients in both directions by default. Previously the encoder was studio-swing but the decoder was full-range, so YUV round trips compressed colors toward grey.
Removed
- Removes the unused internal modules
Image.Nx,Image.Exif.ReadErrorandImage.Exif.FieldNames. These were private implementation modules with no callers.
Image version 0.70.0
Added
-
Adds
Image.Lqip.Cssto encode an image as a packed LQIP CSS placeholder value, with a new guide including the copy-and-paste stylesheet. Thanks to @hlindset for the PR. -
Adds
Image.BackgroundColorto resolve background color specifications (including:average) into concrete pixels; used byImage.rotate/3, affine and warp operations. Thanks to @hlindset for the PRs. -
Adds
:backgroundcolor resolution toImage.write/3so alpha images flatten onto a resolved background when writing to formats without alpha. Thanks to @hlindset for the PR. -
Adds
Image.YUV.valid_encodings/0andImage.YUV.valid_colorspaces/0.
Changed
-
Image.average/1now weights the average by the alpha band so transparent pixels do not contribute; fully transparent images fall back to the unweighted color-band average, and float-format images return unrounded averages. -
All validation and libvips errors are now returned as
{:error, %Image.Error{}}ast:Image.error/0documents; previously many paths returned bare strings. -
Image.to_nx/2withshape: :whcnow performs a true transpose;Image.from_nx/1interprets unnamed tensors as{height, width, bands}and narrows 64-bit integer tensors to 32 bits. -
Image.circle/2center-crops non-square images and merges an existing alpha band instead of adding a second one. -
Image.embed/4honors:mirror/:repeat/:copyextend modes and explicit background colors on images with an alpha band. -
Image.compose/3with a composition list applies top-level options as per-entry defaults instead of ignoring them. -
Image.join/2accepts the documented:topand:centeralignment values.
Fixed
-
Fix the alpha scale for
:lab,:lchand:labsinterpretations inImage.Pixel.to_pixel/3— opaque alpha is255, matching libvips. Thanks to @hlindset for the PR. -
Fix
Image.Math.divide/2for two numbers (it previously subtracted) andImage.dominant_color/2black-bin correction for alpha images. -
Fix
Image.Drawfunctions on greyscale and CMYK images,Image.Shape.line/5end coordinate, andImage.Shape.star/2accepting 3 points as documented. -
Fix crashes on malformed EXIF payloads, non-base83 blurhash input, GIF writes with
:effort, extensionless write paths, andImage.stream!/2with small:buffer_sizevalues. -
Fix
Image.YUVround trips for odd image dimensions andImage.trim/2with an explicit:backgroundon alpha images. -
Fix
Image.thumbnail!/3andImage.straighten_perspective/3error contracts,Image.from_req_stream/2timeout handling, andImage.equalize/2on constant-color bands. -
Fix
Image.write/3to at:File.Stream.t/0to infer the image type from the stream path's file extension when no:suffixoption is given.
Image version 0.69.0
Image version 0.68.0
Image version 0.67.0
Enhancements
-
Adds
Image.vignette/2. -
Adds
Image.Palette.extract/2— perceptual palette extraction from an image via K-means in Oklab plus theColor.Palette.Clustermerge / phantom-guard / centroid-aware-rep pipeline (requires:scholarand:nx). -
Adds
Image.gamma/2— per-band gamma curve adjustment (wrapsVix.Vips.Operation.gamma/2). -
Adds
Image.sepia/2— single-pass sepia tone via a 3×3 colour-recombination matrix; accepts a0.0..1.0strength that blends the matrix with the identity (matching imgix'ssepia=Npercentage). -
Adds
Image.posterize/2— quantises each band to2..256evenly-spaced levels for a flat-shaded, comic-strip rendering. -
Adds
Image.opacity/2— multiplies the alpha band by a0.0..1.0factor; adds an opaque alpha band first when the input has none. -
Adds
Image.set_orientation/2— overrides the EXIF orientation tag without rotating the underlying pixels (paired withImage.open/2's defaultautorotate: falsefor full caller control over orientation; matches imgix'sor=N). -
Adds
:lossyand:chroma_subsamplingoptions toImage.write/3.:lossy(boolean) toggles the lossless wire format on WebP / AVIF and palette-quantisation on PNG.:chroma_subsamplingselects:auto/:on(4:2:0) /:off(4:4:4) on JPEG and AVIF. -
Adds
Image.tint/2— colour-tinted monochrome via a single 3×3 luminance + tint colour-recombination matrix. Used for the imgixmonochrome=#hex/ ImageKite-monochromefamily of CDN options. -
Adds
Image.fade/2— alpha-gradient fade-out on one or more edges via SVG<linearGradient>masks combined with a per-pixel min. Supports:top,:bottom,:left,:right, or:all, with:lengthas either pixels or a fraction of the relevant dimension. Used for Cloudinarye_fade. -
Adds
Image.drop_shadow/2— soft drop shadow under the image's alpha-shaped silhouette. Composites a Gaussian-blurred, opacity-scaled, tinted copy of the alpha band beneath the original. Used for ImageKite-shadowand Cloudinarye_shadow. -
Adds
Image.minimize_metadata/2with a:keepoption — caller-controlled list of EXIF fields to preserve when minimising metadata. The 1-arity variant continues to default to[:copyright, :artist]; the 2-arity variant lets callers passkeep: [:copyright](preserve only copyright),keep: [](strip everything), or any other subset. -
Adds
Image.enhance/2— content-aware automatic enhancement composed of luminance equalisation + mild saturation boost + mild sharpen. Approximates the CDN-style "improve" / "auto-enhance" calls used by Cloudinary, imgix, and ImageKit. Tunable via:saturationand:sharpen_sigmaoptions. -
Adds
Image.to_colorspace/3— ICC-profile-driven colourspace conversion. Accepts the libvips built-in profile atoms (:srgb,:cmyk,:p3) or a path to an.iccfile viaImage.ICCProfile.known?/1validation. Options::input_profile,:intent(:relative/:perceptual/:saturation/:absolute), and:depth(8/16). WrapsVix.Vips.Operation.icc_transform/3.
Removed
Image.QRcodeis removed. QR encoding and decoding move to the siblingimage_qrcodepackage, which is built on Nayuki's QR-Code-generator +quircand does not depend on:evision. Migration: replaceImage.QRcode.encode/2/Image.QRcode.decode/1withImage.QRCode.encode/2/Image.QRCode.decode/1(note the capital "C") and add{:image_qrcode, "~> 0.1"}to your deps. TheImage.to_evision/2andImage.from_evision/1interop helpers are unchanged.
Bug Fixes
Image.add_alpha/2's:opaqueand:transparentatoms now produce alpha = 255 and alpha = 0 respectively, matching the standard libvips / RGBA convention. The previous values were inverted relative to their names; integer values pass through unchanged.
Image version 0.66.0
Enhancements
- Relax Nx support to allow
~> 0.10(not ~> 0.11). This allows Bumblebee to be configured inimage_visionsince Bumblebee only supports Nx~> 0.9.0 or ~> 0.10.0.
Image version 0.65.0
Bug Fixes
- Use the updated colorspace names in Color 0.4.0.
Image version 0.64.0
The primary intent of this release is to stablise the code in readiness for a 1.0 release. Deprecated code has been removed, a standardised color model introduced (via the new library color) and objective classification and detection has been removed to a new image_detection library.
Breaking Changes
-
Five long-deprecated functions have been removed:
Image.interpretation/1— useImage.colorspace/1.Image.type/1(wasformat/1) — useImage.band_format/1.Image.convert_to_mask/1— useImage.convert_alpha_to_mask/1.Image.convert_to_mask!/1— useImage.convert_alpha_to_mask!/1.Image.map_pages/2— useImage.map_join_pages/2.
-
Image.Colorhas been removed. Color handling now lives in two new modules and one new dependency: -
Image.ClassificationandImage.Generationhave moved to a new sibling package,:image_detection. -
:bumblebeeis no longer a dependency of:image. It is configured in the new libraryimage_detection. -
Image.Videois now backed by Xav (a thin Elixir wrapper around FFmpeg) instead of:evision/ OpenCV. The public API surface is largely unchanged but the underlying type, options, and a few semantic details have moved:-
The video struct is now
%Image.Video{}(with fields:reader,:source,:fps,:duration_seconds,:frame_count,:width,:height) rather than%Evision.VideoCapture{}. Pattern-match on the new struct module if your code does so. -
Image.Video.open/2's:backendoption has been removed. FFmpeg picks the demuxer automatically and there is no concept of pluggable backends in Xav. -
Image.Video.known_backends/0,available_backends/0,known_backend?/1,known_backend_values/0, andavailable_backend?/1have been removed for the same reason.Image.Options.Video(the module that owned the backend table) has been deleted. -
Camera input is now opened via a platform-specific device path.
:default_cameraresolves to/dev/video0on Linux,"0"(AVFoundation device 0) on macOS, and"video=0"on Windows. An integer camera index is mapped to the corresponding/dev/videoN(or platform equivalent). For non-default cameras you can also pass an explicit FFmpeg device string. -
Frame-based seeking (
Image.Video.seek/2withframe: n, andImage.Video.image_from_video/2withframe: n) is now implemented as a time-based seek ton / fpsfollowed by zero or morenext_framecalls. For most files this lands on the requested frame; for very inter-frame-compressed files FFmpeg may snap to the nearest preceding keyframe. -
Image.Video.close/1is now a no-op that returns{:ok, %Image.Video{reader: nil}}. Xav garbage-collects the underlying FFmpeg context, so explicit close is no longer necessary. The function is retained for source compatibility; subsequent operations on the closed struct return{:error, %Image.Error{reason: :video_closed}}. -
Image and audio frames are decoded by FFmpeg + libswscale rather than by OpenCV's videoio backend. Pixel-exact comparisons against fixtures generated by the previous version will not match; the test fixture
test/support/validate/video/video_sample_frame_0.pnghas been regenerated.
-
-
:xavis now an optional dependency. It requires FFmpeg ≥ 6.0 to be installed on the system. Add it to yourmix.exsif you useImage.Video:{:xav, "~> 0.10", optional: true} -
:evisionis no longer needed forImage.Video. It is still required forImage.QRcodeand for theImage.to_evision/2/Image.from_evision/1interop helpers, which are unchanged. The README's optional-dependency table reflects the new split. -
Image.Erroris now a structured public exception. It carries:reason(atom or{atom, value}tuple),:operation,:path,:value, and a derived:message. Every fallible function in the library now returns{:ok, value}or{:error, %Image.Error{}}— bare-string error tuples have been eliminated. Bang variants raise the same struct. The newImage.Error.wrap/2helper attaches structured context to a raw libvips orFile.*error. Pattern-match on:reasoninstead of scraping:message:case Image.open(path) do {:ok, image} -> ... {:error, %Image.Error{reason: :enoent}} -> not_found_handler() {:error, %Image.Error{} = err} -> raise err end
Enhancements
-
Image.dominant_color/2now accepts a:methodoption of either:histogram(the existing default) or:imagequant. The:imagequantmethod routes throughlibimagequant(viavips_gifsave_buffer) and returns a palette of{r, g, b}tuples ordered by perceptual importance. New:effortand:ditheroptions tune the quantiser. Seeguides/performance.mdfor a comparison of the two methods. -
Colour arguments to drawing, embedding, trimming, gradient, chroma key, comparison, warp-perspective, meme, replace-colour, flatten, and
if_then_elseoperations are now correctly converted to the target image's colour space. Drawing:redon a Lab image now produces actual Lab red, not the bytes[255, 0, 0]reinterpreted as Lab. -
New
Image.PixelandImage.ICCProfilemodules.Image.Pixel.to_pixel/3is the canonical way to turn any user-friendly colour input into a libvips-ready pixel for a particular image;Image.Pixel.to_srgb/1is the image-independent equivalent for callers (SVG renderers, gradients) that need a fixed sRGB output. -
The
:colorlibrary is now a dependency of:image. It is now the canonical colour science layer for the project. -
Image.Videonow supports HTTP/HTTPS/RTSP/RTMP URLs as video sources for free, since FFmpeg supports them natively. -
Image.xav_configured?/0is the new compile-time predicate that gates theImage.Videomodule (analogous toImage.evision_configured?/0andImage.bumblebee_configured?/0). -
The
Image.Video.frame_to_image/1helper exposes the rawXav.Frame→Vix.Vips.Image.t()conversion (used internally byimage_from_video/2andstream!/2). Useful if you have a frame from elsewhere in the Xav ecosystem and want to bring it intoImage.
Image version 0.63.0
Image version 0.62.1
Bug Fixes
-
Fix decoding EXIF component configuration if the value is invalid. Fixes #194. Thanks to @ethangunderson for the report.
-
Fix
Image.minimize_metadata/1when the image does not have an author or copyright field.