Releases: elixir-image/image
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.
Image version 0.62.0
Breaking Change
Image.histogram/1previously normalized the results which meant that the pixel counts for each bucket could not be resolved. The function no longer normalises the histogram so the raw pixel counts per bucket are retained.
Bug Fixes
-
Image.histogram/1is fixed to not normalize histogram entries. Therefore the histogram now returns correct pixel counts. -
Fix
Image.Text.add_background_padding/2when the padding is derived from a base image.
Enhancements
-
Add
Image.to_list/1to return an image as a nested list. -
Added an example for
Image.histogram/1to illustrate what data is returned and how to interpret it.
Image version 0.61.1
Bug Fixes
- Fix "function get_req_message/1" compiler warning.
Image version 0.61.0
Enhancements
- Adds
Image.from_req_stream/2. This function returns aVix.Vips.Image.t/0from streaming aReqrequest using theReq.get/2optioninto: :self,
Image version 0.60.0
Breaking Changes
-
Image.Math.maxpos/2is renamed toImage.Math.top_n/2to better reflect its intent. The keyword options argument is also replaced with a simple integer argumentn. -
Image.Math.minpos/2is renamed toImage.Math.bottom_n/2to better reflect its intent. The keyword options argument is also replaced with a simple integer argumentn. -
The return value from
Image.Math.top_n/2andImage.Math.bottom_n/2have changed. They will now return the form{max, max_x, max_y, [{x_max_1, y_max_1}, {x_max_2, y_max_2}, ...]}.
Bug Fixes
- Improve the error messages for
Image.crop/5when the crop bounding box is invalid. Closes #190.
Enhancements
-
Add
Image.band_and/1,Image.band_or/1andImage.band_xor/1to apply the appropriate boolean operation across the bands of an image. -
Add new (and different)
Image.Math.maxpos/2andImage.Math.minpos/2which return only coordinates whose values match the image maximum or minimum.