diff --git a/README.md b/README.md
index 459f6ed..e07a131 100644
--- a/README.md
+++ b/README.md
@@ -4,199 +4,170 @@
[](https://hex.pm/packages/vix)
[](https://hexdocs.pm/vix/)
-Vix is an Elixir extension for the [libvips](https://libvips.github.io/libvips/) image processing library.
-About libvips from its documentation:
+Blazing fast image processing for Elixir powered by [libvips](https://libvips.github.io/libvips/), the same engine that powers [sharp.js](https://github.com/lovell/sharp).
-> libvips is a [demand-driven, horizontally threaded](https://github.com/libvips/libvips/wiki/Why-is-libvips-quick) image processing library. Compared to similar libraries, [libvips runs quickly and uses little memory](https://github.com/libvips/libvips/wiki/Speed-and-memory-use).
+## Perfect For
-## About Vix
+- Building image processing APIs and services
+- Generating thumbnails at scale
+- Image manipulation in web applications
+- Computer vision preprocessing
+- Processing large scientific/satellite images
-Vix is a **NIF**-based bindings library for libvips.
+## Features
-**Major Features:**
+- **High Performance**: Uses libvips' demand-driven, horizontally threaded architecture
+- **Memory Efficient**: Processes images in chunks, perfect for large files
+- **Streaming Support**: Read/write images without loading them fully into memory
+- **Rich Ecosystem**: Zero-copy integration with [Nx](https://hex.pm/packages/nx) and [eVision](https://hex.pm/packages/evision)
+- **Zero Setup**: Pre-built binaries for MacOS and Linux platforms included.
+- **Auto-updating API**: New libvips features automatically available
+- **Comprehensive Documentation**: [Type specifications and documentation](https://hexdocs.pm/vix/Vix.Vips.Operation.html) for 300+ operations
-* Vix can take full advantage of libvips [optimizations](https://libvips.github.io/libvips/API/current/How-it-works.md.html), such as joining operations in the pipeline and caching, since Vix is a native binding.
-* Experimental support for streaming. User can read or write images without keeping the complete image in memory. See `Vix.Vips.Image.new_from_enum/1` and `Vix.Vips.Image.write_to_stream/2`
-* Efficient interoperability (zero-copy) with other libraries, such as Nx and eVision. See `Vix.Vips.Image.new_from_binary/5` and `Vix.Vips.Image.write_to_tensor/1`
-* By default, Vix provides pre-built NIF and libvips binaries for major platforms, so don't worry about handling the libvips dependencies or compiling the NIF. Just add Vix and you are good to go! See below for more details.
-* Ergonomic bindings with auto-generated documentation for operations using vips introspection, so they always match the installed libvips version. If a newer libvips version updates `adds` or `modify` operations, you don't have to wait for Vix to be updated — bindings for the operations (along with documentation) will be available automatically.
-
-Check [Vips operation documentation](https://hexdocs.pm/vix/Vix.Vips.Operation.html) for the list of available operations and [type specifications](https://hexdocs.pm/vix/Vix.Vips.Operation.html#types).
-
-### Pre-compiled NIF and libvips
-
-Starting from v0.16.0, Vix can use either pre-built binaries or platform-provided binaries.
-
-By default, Vix provides pre-built NIF and libvips and uses them for operations. This makes deployment and release of your application simple. No need to install any compiler toolchain or dependencies to use Vix. Pre-built libvips supports reading these formats: SVG, PNG, TIFF, JPEG, WEBP, RAW, HEIF, and GIF. If you find that the pre-built libvips is missing support for an image format, you can bring your own libvips by installing it manually and configuring Vix to use that instead. Vix makes sure to generate relevant functions and documentation based on the dependencies you bring. For example, if you install libvips with dzsave support, Vix will generate dzsave bindings for you.
-
-You can choose this using the environmental variable, `VIX_COMPILATION_MODE`. This variable must be set during compilation and at runtime. Possible values are:
-
-* `PRECOMPILED_NIF_AND_LIBVIPS` (Default): Uses the Vix-provided NIF and libvips. No need to install any additional dependencies. Big thanks to the [sharp](https://github.com/lovell/sharp) library maintainers, which pre-compiled libvips is based on: https://github.com/lovell/sharp-libvips/.
-
- Run the command below to generate the required `checksum.exs` file.
-
- ```sh
- MIX_ENV=dev mix elixir_make.checksum --all --ignore-unavailable
- ```
-
-* `PLATFORM_PROVIDED_LIBVIPS`: Uses the platform-provided libvips. NIF will be compiled during compilation phase. Install the required build tools to compile the NIF. To build a NIF you need the following:
-
- - libvips with development headers
- * **macOS**: using brew `brew install libvips`
- * **Linux**: using deb `apt install libvips-dev`
- For more details see https://www.libvips.org/install.html
- - `pkg-config`
- - C compiler
-
-#### Should I use Vix or [Image](https://github.com/kipcole9/image)?
-
-Vix is focused on bridging the BEAM and libvips. It tries to stay close to the libvips interface in order to support a large set of use cases, so some basic operations might feel unintuitive. [Image](https://github.com/kipcole9/image), an excellent library by [@kipcole9](https://github.com/kipcole9), builds on top of Vix and provides more Elixir-friendly wrapper functions for common operations, along with many additional features: handling Exif, Math operators, and more. And all of this is accompanied by good documentation, so for most, using `Vix` via `Image` might be better choice.
-
-## Introduction
-
-The easiest way to get started or explore the operations is to run the Introduction Livebook.
-
-[](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Fintroduction.livemd)
+## Quick Start
```elixir
-# print vips version
-IO.puts("Version: " <> Vix.Vips.version())
-
-# contains image read/write functions
-alias Vix.Vips.Image
-
-# Reading an image from a file. Note that the image is not actually loaded into memory at this point.
-# `img` is an `%Image{}` struct.
-{:ok, img} = Image.new_from_file("~/Downloads/kitty.png")
-
-# You can also load an image from a binary, so you can work with images without touching the file system.
-# It tries to guess the image format from the binary and uses the correct loader.
+Mix.install([
+ {:vix, "~> 0.23"}
+])
-bin = File.read!("~/Downloads/kitty.png")
-{:ok, %Image{} = img} = Image.new_from_buffer(bin)
+alias Vix.Vips.{Image, Operation}
-# If you know image format beforehand, you can use the appropriate function from
-# `Vix.Vips.Operation`. For example, use `Vix.Vips.Operation.pngload_buffer/2` to load a PNG.
+# Read an image
+{:ok, img} = Image.new_from_file("profile.jpg")
-bin = File.read!("~/Downloads/kitty.png")
-{:ok, {img, _flags}} = Vix.Vips.Operation.pngload_buffer(bin)
-
-# writing an `Image` to a file.
-# Image type selected based on the image path extension. See documentation for more options
-:ok = Image.write_to_file(img, "kitty.jpg[Q=90]")
-
-# let's print the image dimensions
-IO.puts("Width: #{Image.width(img)}")
-IO.puts("Height: #{Image.height(img)}")
+# Create a thumbnail and optimize for web
+{:ok, thumb} = Operation.thumbnail(img, 300)
+:ok = Image.write_to_file(thumb, "thumbnail.jpg", Q: 90, strip: true, interlace: true)
+```
+[👉 Try in Livebook](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Fintroduction.livemd)
-# Operations
+
-# contains image processing operations
-alias Vix.Vips.Operation
+## Common Operations
-# getting a rectangular region from the image (crop)
-{:ok, extract_img} = Operation.extract_area(img, 100, 50, 200, 200)
+### Basic Processing
+```elixir
+# Resize preserving aspect ratio
+{:ok, resized} = Operation.resize(img, 0.5) # 50% of original size
-# create image thumbnail
-#
-# This operation is significantly faster than normal resize
-# due to several optimizations such as shrink-on-load.
-# You can read more about it in the libvips docs: https://github.com/libvips/libvips/wiki/HOWTO----Image-shrinking
-#
-# Check Vix docs for more details about several optional parameters
-width = 100
-{:ok, thumb} = Operation.thumbnail("~/Downloads/dog.jpg", width)
+# Crop a section
+{:ok, cropped} = Operation.crop(img, 100, 100, 500, 500)
+# Rotate with white background
+{:ok, rotated} = Operation.rotate(img, 90, background: [255, 255, 255])
-# resize the image to 400x600. `resize` function accepts scaling factor.
-# Skip `vscale` if you want to preserve aspect ratio
-hscale = 400 / Image.width(img)
-vscale = 600 / Image.height(img)
-{:ok, resized_img} = Operation.resize(img, hscale, vscale: vscale)
+# Smart thumbnail (preserves important features)
+# See:
+{:ok, thumb} = Operation.thumbnail("large.jpg", 300, size: :VIPS_SIZE_DOWN, crop: :VIPS_INTERESTING_ATTENTION)
+```
-# flip the image
-{:ok, flipped_img} = Operation.flip(img, :VIPS_DIRECTION_HORIZONTAL)
+### Web Optimization
+```elixir
+# Convert to WebP with quality optimization
+:ok = Image.write_to_file(img, "output.webp", Q: 80, effort: 4)
-# Gaussian blur
-{:ok, blurred_img} = Operation.gaussblur(img, 5)
+# Create progressive JPEG with metadata stripped
+:ok = Image.write_to_file(img, "output.jpg", interlace: true, strip: true, Q: 85)
-# convert the image to grayscale
-{:ok, bw_img} = Operation.colourspace(img, :VIPS_INTERPRETATION_B_W)
+# Generate multiple formats
+:ok = Image.write_to_file(img, "photo.avif", Q: 60)
+:ok = Image.write_to_file(img, "photo.webp", Q: 80)
+:ok = Image.write_to_file(img, "photo.jpg", Q: 85)
+```
-# adding gray border
-{:ok, extended_img} =
- Operation.embed(img, 10, 10, Image.width(img) + 20, Image.height(img) + 20,
- extend: :VIPS_EXTEND_BACKGROUND,
- background: [128]
- )
+### Filters & Effects
+```elixir
+# Blur
+{:ok, blurred} = Operation.gaussblur(img, 3.0)
-# rotate the image 90 degrees clockwise
-{:ok, rotated_img} = Operation.rot(img, :VIPS_ANGLE_D90)
+# Sharpen
+{:ok, sharp} = Operation.sharpen(img, sigma: 1.0)
-# join two images horizontally
-{:ok, main_img} = Image.new_from_file("~/Downloads/kitten.svg")
-{:ok, joined_img} = Operation.join(img, main_img, :VIPS_DIRECTION_HORIZONTAL, expand: true)
+# Grayscale
+{:ok, bw} = Operation.colourspace(img, :VIPS_INTERPRETATION_B_W)
+```
-# render text as image
-# see https://libvips.github.io/libvips/API/current/libvips-create.html#vips-text for more details
-{:ok, {text, _}} = Operation.text(~s(Vix is awesome!), dpi: 300, rgba: true)
-# add text to an image
-{:ok, img_with_text} = Operation.composite2(img, text, :VIPS_BLEND_MODE_OVER, x: 50, y: 20)
+### Advanced Usage
+```elixir
+# Smart thumbnail preserving important features
+{:ok, thumb} = Operation.thumbnail(
+ "large.jpg",
+ 300,
+ size: :VIPS_SIZE_DOWN, # only downsize, it will just copy if asked to upsize
+ crop: :VIPS_INTERESTING_ATTENTION
+)
+
+# Process image stream on the fly
+{:ok, image} =
+ File.stream!("large_photo.jpg", [], 65_536)
+ |> Image.new_from_enum()
+# use `image` for further operations...
+
+# Stream image to S3
+:ok =
+ Image.write_to_stream(image, ".png")
+ |> Stream.each(&upload_chunk_to_s3/1)
+ |> Stream.run()
+```
+
+
+
+
+
-## Creating GIF
-black = Operation.black!(500, 500, bands: 3)
+## Performance
-# create images with different grayscale values
-frames = Enum.map(1..255//10, fn n ->
- Operation.linear!(black, [1], [n/255,n/255,n/255])
-end)
+Libvips very fast and uses very little memory. See the detailed benachmark. Resizing an image is typically 4x-5x faster than using the quickest ImageMagick settings. It can also work with very large images without completely loading them to the memory.
-{:ok, joined_img} = Operation.arrayjoin(frames, across: 1)
+## Installation
-# set frame delay metadata. See `Image.mutate` documentation for more details
-{:ok, joined_img} =
- Image.mutate(joined_img, fn mut_img ->
- frame_delay = List.duplicate(100, length(frames))
- :ok = Vix.Vips.MutableImage.set(mut_img, "delay", :VipsArrayInt, frame_delay)
- end)
+Add Vix to your dependencies:
-:ok = Operation.gifsave(joined_img, Path.expand("~/Downloads/bw.gif"), "page-height": 500)
+```elixir
+def deps do
+ [
+ {:vix, "~> x.x.x"}
+ ]
+end
```
-The [libvips reference manual](https://libvips.github.io/libvips/API/current/) has more detailed documentation about the operations.
+That's it! Vix includes pre-built binaries for MacOS & Linux.
-### Livebooks
+## Advanced Setup
-* Livebook implementing picture language defined in [*Structural and Interpretation of Computer Programs*](https://mitpress.mit.edu/sites/default/files/sicp/index.html) section [2.2.4](https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-15.html#%_sec_2.2.4).
+Want to use your system's libvips? Set before compilation:
-[](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Fpicture-language.livemd)
-
-* Creating Rainbow. Quick introduction to complex numbers and operations `mapim` and `buildlut`.
+```bash
+export VIX_COMPILATION_MODE=PLATFORM_PROVIDED_LIBVIPS
+```
-[](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Frainbow.livemd)
+See [libvips installation guide](https://www.libvips.org/install.html) for more details.
-* Auto correct Document Rotation. Quick introduction to Fourier Transformation, Complex planes, and Arithmetic Operations.
-[](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Fauto_correct_rotation.livemd)
+## Documentation & Resources
-### NIF Error Logging
+- [Complete API Documentation](https://hexdocs.pm/vix/)
+- [Interactive Introduction (Livebook)](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Fintroduction.livemd)
+- [Creating Rainbow Effects (Livebook)](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Frainbow.livemd)
+- [Auto Document Rotation (Livebook)](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Fauto_correct_rotation.livemd)
+- [Picture Language from SICP (Livebook)](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fakash-akya%2Fvix%2Fblob%2Fmaster%2Flivebooks%2Fpicture-language.livemd)
-Vix NIF code writes logs to stderr on certain errors. This is disabled by default. To enable logging set `nif_logger_level` to `:error`. Defaults to `:none`
+## FAQ
-```elixir
-config :vix, nif_logger_level: :error
-```
+### Should I use Vix or Image?
+- [Image](https://github.com/kipcole9/image) is a library which builds on top of Vix and others. Use Image if you want a more Elixir-friendly API for common operations or if you want higher level operations such as Blurhash.
+- Use Vix directly if you
+ - need advanced features
+ - building image processing pipeline which is more than few lines
+ - only need libvips and want to be close to the metal
+### What image formats are supported?
+Out of the box: JPEG, PNG, WEBP, TIFF, SVG, HEIF, GIF, and more. Need others? Just install libvips with the required libraries!
-## Installation
+## License
-```elixir
-def deps do
- [
- {:vix, "~> x.x.x"}
- ]
-end
-```
+MIT License - see [LICENSE](LICENSE) for details.
diff --git a/lib/vix/vips/image.ex b/lib/vix/vips/image.ex
index fc9aef3..8553ccf 100644
--- a/lib/vix/vips/image.ex
+++ b/lib/vix/vips/image.ex
@@ -1,98 +1,76 @@
defmodule Vix.Vips.Image do
@moduledoc """
- Functions for reading and writing images as well as
- accessing and updating image metadata.
+ Primary module for reading and writing image and image metadata.
- ## Access syntax (slicing)
+ This module allows you to read, write, manipulate and analyze images efficiently using the powerful
+ libvips image processing library. It offers operations like loading images, accessing metadata,
+ and extracting image bands.
- Vix images implement Elixir's access syntax. This allows developers
- to slice images and easily access sub-dimensions and values.
+ ## Basic Usage
- ### Integer
- Access accepts integers. Integers will extract an image band using parameter as index:
+ # Load an image from file
+ {:ok, image} = Image.new_from_file("path/to/image.jpg")
- #=> {:ok, i} = Image.new_from_file("./test/images/puppies.jpg")
- {:ok, %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153539>}}
- #=> i[0]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153540>}
+ # Create a new RGB image
+ {:ok, blank} = Image.build_image(width, height, [0, 0, 0])
- If a negative index is given, it accesses the band from the back:
+ ## Access Syntax (Image Slicing)
- #=> i[-1]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153540>}
+ The module implements Elixir's Access behavior, providing an intuitive way to slice and extract
+ image data across three dimensions: width, height, and bands (color channels).
- Out of bound access will throw an `ArgumentError` exception:
+ ### Band Extraction
- #=> i[-4]
- ** (ArgumentError) Invalid band requested. Found -4
+ Access individual color bands using integer indices:
- ### Range
+ # Get the red channel from an RGB image
+ red_channel = image[0]
- Access also accepts ranges. Ranges in Elixir are inclusive:
+ # Get the alpha channel (last band) from an RGBA image
+ alpha = image[-1]
- #=> i[0..1]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153641>}
+ ### Band Ranges
- Ranges can receive negative positions and they will read from
- the back. In such cases, the range step must be explicitly given
- (on Elixir 1.12 and later) and the right-side of the range must
- be equal or greater than the left-side:
+ Extract multiple consecutive bands using ranges:
- #=> i[0..-1//1]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153703>}
+ # Get red and green channels from RGB
+ red_green = image[0..1]
- To slice across multiple dimensions, you can wrap the ranges in a list.
- The list will be of the form `[with_slice, height_slice, band_slice]`.
+ # Get all channels.
+ all_channels = image[0..-1//1]
+ # Same as `all_channels = image`
- # Returns an image that slices a 10x10 pixel square
- # from the top left of the image with three bands
- #=> i[[0..9, 0..9, 0..3]]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153738>}
+ ### Dimensional Slicing
- If number of dimensions are less than 3 then remaining dimensions
- are returned in full
+ Slice images across multiple dimensions using lists of the form [width, height, bands]:
- # If `i` size is 100x100 with 3 bands
- #=> i[[0..9, 0..9]] # equivalent to `i[[0..9, 0..9, 0..2]]`
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153740>}
+ # Get a 100x100 pixel square from the top-left corner
+ top_left = image[[0..99, 0..99]]
- #=> i[[0..9]] # equivalent to `i[[0..9, 0..99, 0..2]]`
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153703>}
+ # Get the bottom-right 50x50 pixel square
+ bottom_right = image[[-50..-1, -50..-1]]
- Slices can include negative ranges in which case the indexes
- are calculated from the right and bottom of the image.
+ # Get the bottom-right 50x50 pixel square, and only green channel
+ bottom_right = image[[-50..-1, -50..-1, 1]]
- # Slices the bottom right 10x10 pixels of the image
- # and returns all bands.
- #=> i[[-10..-1, -10..-1]]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153742>}
+ ### Named Dimension Access
- Slice can mix integers and ranges
+ Use keyword lists for more explicit dimension specification:
- # Slices the bottom right 10x1 pixels of the image
- # and returns all bands.
- #=> i[[-10..-1, -1]]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153742>}
+ # Get first 200 pixels in width, maintaining full height and bands
+ slice = image[[width: 0..199]]
- ### Keyword List
+ # Get specific height range with all bands
+ middle = image[[height: 100..299]]
- Access also accepts keyword list. Where key can be any of `width`,
- `height`, `band`. and value must be an `integer`, `range`. This is
- useful for complex scenarios when you want omit dimensions arbitrary
- dimensions.
+ # Extract specific band
+ green = image[[band: 1]]
- # Slices an image with height 10 with max width and all bands
- #=> i[[height: 0..10]]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153742>}
+ # Get a 100x100 pixel square from the top-left corner, and only red-green channels
+ bottom_right = image[[width: 0..99, height: 0..99, band: 0..1]]
- # Slices an image with single band 1
- #=> i[[band: 1]]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153742>}
+ See `Vix.Vips.Operation` for available image processing operations.
- # Slices the bottom right 10x10 pixels of the image
- # and returns all bands.
- #=> i[[width: -10..-1, height: -10..-1]]
- %Vix.Vips.Image{ref: #Reference<0.2448791511.2685009949.153742>}
"""
defstruct [:ref]
@@ -149,6 +127,42 @@ defmodule Vix.Vips.Image do
@impl Access
+ @doc """
+ Extracts a band from an image using Access syntax.
+
+ This function implements the Access behaviour for images, enabling array-like
+ syntax for extracting bands and slices. See the module documentation for
+ detailed examples of Access syntax usage.
+
+ ## Parameters
+
+ * `image` - The source image
+ * `band` - Integer index, Range, or list specifying what to extract
+
+ ## Returns
+
+ * `{:ok, image}` with extracted data
+ * Raises ArgumentError for invalid access patterns
+
+ Access is read-only - `get_and_update/3` and `pop/2` are not supported.
+
+ ## Examples
+
+ # Get red channel
+ {:ok, red} = Image.fetch(rgb_image, 0)
+
+ # Get first two channels
+ {:ok, rg} = Image.fetch(rgb_image, 0..1)
+
+ # Get 100x100 region from top-left
+ {:ok, region} = Image.fetch(image, [0..99, 0..99])
+
+ # Get specific height range
+ {:ok, slice} = Image.fetch(image, [height: 100..199])
+
+ See `Vix.Vips.Image` module docs for more details
+ """
+
# Extract band when the band number is positive or zero
def fetch(image, band) when is_integer(band) and band >= 0 do
case Operation.extract_band(image, band) do
@@ -307,16 +321,32 @@ defmodule Vix.Vips.Image do
end
@doc """
- Builds an Image
+ Creates a new image with specified dimensions and background values.
+
+ Takes width, height, and a list of background values to create a new image. The background values
+ determine both the number of bands and initial pixel values.
+
+ ## Parameters
+
+ * `width` - Width of the image in pixels (positive integer)
+ * `height` - Height of the image in pixels (positive integer)
+ * `background` - List of numbers representing initial pixel values for each band. Defaults to [0, 0, 0]
+ * `opts` - Keyword list of options
## Options
- * `interpretation` : must be a valid vips_interpretation or `:auto`. When value is
- `:auto` it will be set based on the number of bands in the `background`. Defaults to `:auto`
+ * `:interpretation` - Color space interpretation. Can be a valid `vips_interpretation` or `:auto`.
+ When `:auto`, determined by number of bands:
+ * 1 band -> `:VIPS_INTERPRETATION_B_W`
+ * 3 bands -> `:VIPS_INTERPRETATION_RGB`
+ * 4 bands -> `:VIPS_INTERPRETATION_sRGB`
+ * other -> `:VIPS_INTERPRETATION_MULTIBAND`
- * `format` : must be a valid vips_format or `:auto`. When value is `:auto` it will
- be set to a format just large enough to hold all the values. Ex, if any of the
- value is a float then format will be `:VIPS_FORMAT_DOUBLE`
+ * `:format` - Pixel value format. Can be a valid vips_format or `:auto`.
+ When `:auto`, determined by value ranges. For example:
+ * 0-255 -> `:VIPS_FORMAT_UCHAR`
+ * decimal values -> `:VIPS_FORMAT_DOUBLE`
+ * larger integers -> `:VIPS_FORMAT_INT`
## Examples
@@ -328,7 +358,8 @@ defmodule Vix.Vips.Image do
{1, 2, 1}
```
- Correctly sets interpretation
+ Sets the interpretation based on the bands
+
```elixir
iex> {:ok, img} = Image.build_image(1, 2, [10])
iex> Image.interpretation(img)
@@ -344,7 +375,8 @@ defmodule Vix.Vips.Image do
:VIPS_INTERPRETATION_MULTIBAND
```
- Correctly sets format
+ Sets the band format based on the values
+
```elixir
iex> {:ok, img} = Image.build_image(1, 2, [10, 9, 220])
iex> Image.format(img)
@@ -363,7 +395,6 @@ defmodule Vix.Vips.Image do
:VIPS_FORMAT_CHAR
```
-
"""
@spec build_image(
pos_integer,
@@ -388,9 +419,9 @@ defmodule Vix.Vips.Image do
end
@doc """
- Builds an Image
+ Creates a new image with specified dimensions and background values.
- Same as `build_image/3` but raises error instead of returning it.
+ Similar to `build_image/4` but raises `Image.Error` on failure instead of returning error tuple.
## Examples
@@ -402,7 +433,8 @@ defmodule Vix.Vips.Image do
{1, 2, 1}
```
- See `build_image/3` for more detailed examples.
+ See `build_image/4` for detailed documentation.
+
"""
@spec build_image!(pos_integer, pos_integer, [number]) :: t() | no_return
def build_image!(width, height, background \\ [0, 0, 0]) do
@@ -413,34 +445,51 @@ defmodule Vix.Vips.Image do
end
@doc """
- Opens `path` for reading, returns an instance of `t:Vix.Vips.Image.t/0`
+ Opens an image file for reading and returns a `t:Vix.Vips.Image.t/0` struct.
+
+ This function provides a high-level interface to load images from many format
+ depending on the libraries installed.
- It can load files in many image formats, including VIPS, TIFF, PNG,
- JPEG, FITS, Matlab, OpenEXR, CSV, WebP, Radiance, RAW, PPM and
- others.
+ ## Options
- Optional param `opts` is passed to the image loader. Available
- options depends on the file format. You can find all options
- available for a format under operation function in
- [Operation](./search.html?q=load+-buffer+-filename+-profile) module.
+ The `opts` parameter accepts format-specific loading options. Each format supports
+ different options which can be found in the [Operation](./search.html?q=load+-buffer+-filename+-profile)
+ module documentation.
- For example, you can find all of the options supported by
- JPEG under `Vix.Vips.Operation.jpegload/2` function documentation.
+
+ ## Examples
```elixir
- Image.new_from_file("fred.jpg", shrink: 2)
+ # Basic usage:
+ {:ok, %Image{} = image} = Image.new_from_file("photo.jpg")
+
+ # Loading with options (downsampling by factor of 2):
+ {:ok, image} = Image.new_from_file("large_photo.jpg", shrink: 2)
+
+ # Loading a specific page from a multi-page TIFF
+ {:ok, page} = Image.new_from_file("document.tiff", page: 1)
+
+ # Loading a PNG with specific options:
+ {:ok, image} = Image.new_from_file("transparent.png", access: :VIPS_ACCESS_SEQUENTIAL)
```
- Opens "fred.jpg", downsampling by a factor of two.
+ To see all available options for a specific format, you can check the corresponding loader function. For example, `Vix.Vips.Operation.jpegload/2` documents all JPEG-specific options.
- > #### Loading is fast {: .info}
- > Only enough of the image is loaded to the memory to be able to
- > fill out the header. Pixels will only be decompressed when they are
- > needed.
+ ## Performance Notes
- If you want more control over the loader, Use the specific format loader
- from `Vix.Vips.Operation`. For example for jpeg use
- `Vix.Vips.Operation.jpegload/2`
+ The loading process is optimized - only the image header is initially loaded into memory.
+ Pixel data is decompressed on-demand when accessed, making this operation memory-efficient
+ for large images.
+
+ ## Advanced Usage
+
+ For more control over the loading process, consider using format-specific loaders from
+ `Vix.Vips.Operation`. For example:
+
+ ```elixir
+ # Using specific JPEG loader
+ {:ok, image} = Vix.Vips.Operation.jpegload("photo.jpg", access: :VIPS_ACCESS_SEQUENTIAL)
+ ```
"""
@spec new_from_file(String.t(), keyword) :: {:ok, t()} | {:error, term()}
@@ -463,11 +512,29 @@ defmodule Vix.Vips.Image do
end
@doc """
- Create a new image based on an existing image with each pixel set to `value`
+ Creates a new image by cloning dimensions and properties from an existing image,
+ filling all bands with specified values.
+
+ The new image inherits the following properties from the source image:
+ * Width and height
+ * Format and color interpretation
+ * Resolution
+ * Offset
+
+ ## Parameters
+
+ * `image` - Source image to clone properties from
+ * `value` - List of numbers representing values for each band
+
+ ## Examples
+
+ Create a solid red image with same dimensions as source:
+
+ {:ok, red_image} = Image.new_from_image(source_image, [255, 0, 0])
+
+ Create a semi-transparent overlay:
- Creates a new image with width, height, format, interpretation,
- resolution and offset taken from the input image, but with each band
- set from `value`.
+ {:ok, overlay} = Image.new_from_image(source_image, [0, 0, 0, 128])
"""
@spec new_from_image(t(), [number()]) :: {:ok, t()} | {:error, term()}
def new_from_image(%Image{ref: vips_image}, value) do
@@ -478,30 +545,37 @@ defmodule Vix.Vips.Image do
end
@doc """
- Create a new image from formatted binary
+ Creates a new image from formatted binary data (like JPEG, PNG, etc.).
- Create a new image from formatted binary `bin`. Binary should be an
- image encoded in a format such as JPEG. It tries to recognize the
- format by checking the binary.
+ This function attempts to automatically detect the image format from the binary data.
+ It's particularly useful when working with image data from network requests, databases,
+ or other binary sources.
- If you already know the image format of `bin` then you can just use
- corresponding loader operation function directly from
- `Vix.Vips.Operation` instead. For example to load jpeg, you can use
- `Vix.Vips.Operation.jpegload_buffer/2`
+ ## Parameters
- `bin` should be formatted binary (ie. JPEG, PNG etc). For loading
- unformatted binary (raw pixel data) see `new_from_binary/5`.
+ * `bin` - Binary data containing a formatted image (JPEG, PNG, etc.)
+ * `opts` - Format-specific loading options (same as `new_from_file/2`)
- Optional param `opts` is passed to the image loader. Options
- available depend on the file format. You can find all options
- available like this:
+ ## Examples
- ```sh
- $ vips jpegload_buffer
- ```
+ Basic usage with binary data:
+
+ {:ok, image} = Image.new_from_buffer(jpeg_binary)
+
+ Loading with specific options:
+
+ {:ok, image} = Image.new_from_buffer(jpeg_binary, shrink: 2)
+
+ Working with HTTP responses:
+
+ {:ok, response} = HTTPClient.get("https://example.com/image.jpg")
+ {:ok, image} = Image.new_from_buffer(response.body)
+
+ ## Format-Specific Loading
- Not all loaders support load from buffer, but at least JPEG, PNG and
- TIFF images will work.
+ For known formats, you can use specific loaders from `Vix.Vips.Operation`:
+
+ {:ok, image} = Vix.Vips.Operation.jpegload_buffer(jpeg_binary, access: :VIPS_ACCESS_SEQUENTIAL)
"""
@spec new_from_buffer(binary(), keyword()) :: {:ok, t()} | {:error, term()}
def new_from_buffer(bin, opts \\ []) do
@@ -513,39 +587,62 @@ defmodule Vix.Vips.Image do
end
@doc """
- Create a new image from raw pixel data
+ Creates a new image from raw pixel data with zero-copy performance.
+
+ This function wraps raw pixel data without copying, making it highly efficient for
+ integrating with other imaging libraries or processing pipelines. It's particularly
+ useful when working with raw pixel data from libraries like [`eVision`](https://github.com/cocoa-xu/evision) or
+ [`Nx`](https://github.com/elixir-nx/).
- Creates an image by wrapping passed raw pixel data. This function
- does not copy the passed binary, instead it just creates a reference
- to the binary term (zero-copy). So this function is very efficient.
+ ## Parameters
- This function is useful when you are getting raw pixel data from
- some other library like
- [`eVision`](https://github.com/cocoa-xu/evision) or
- [`Nx`](https://github.com/elixir-nx/) and want to perform some
- operation on it using Vix.
+ * `bin` - Binary containing raw pixel data in left-to-right, top-to-bottom order
+ * `width` - Image width in pixels
+ * `height` - Image height in pixels
+ * `bands` - Number of bands per pixel (e.g., 3 for RGB, 4 for RGBA)
+ * `band_format` - Format of each band (typically `:VIPS_FORMAT_UCHAR`)
- Binary should be sequence of pixel data, for example: RGBRGBRGB. and
- order should be left-to-right, top-to-bottom.
+ ## Endianness Requirements
- `bands` should be number values which represent the each pixel. For
- example: if each pixel is RGB then `bands` will be 3. If each pixel
- is RGBA then `bands` will be 4. `band_format` refers to type of
- each band. Usually it will be `:VIPS_FORMAT_UCHAR`.
+ The binary data MUST be in native endianness. When using bitstring syntax, always
+ specify the `native` modifier:
- `bin` should be raw pixel data binary. For loading
- formatted binary (JPEG, PNG) see `new_from_buffer/2`.
+ # Correct - using native endianness
+ <>
- ## Endianness
+ # Incorrect - default big endian
+ <>
- Byte order of the data *must* be in native endianness. This matters
- if you are generating or manipulating binary by using bitstring
- syntax. By default bitstring treat binary byte order as `big` endian
- which might *not* be native. Always use `native` specifier to
- ensure. See [Elixir
- docs](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#%3C%3C%3E%3E/1-endianness)
+ See [Elixir docs](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#%3C%3C%3E%3E/1-endianness)
for more details.
+ ## Examples
+
+ Creating an RGB image from raw pixel data
+
+ ```elixir
+ pixels = <<
+ 255, 0, 0, # Red pixel
+ 0, 255, 0, # Green pixel
+ 0, 0, 255 # Blue pixel
+ >>
+ {:ok, image} = Image.new_from_binary(pixels, 3, 1, 3, :VIPS_FORMAT_UCHAR)
+ ```
+
+ Working with grayscale data:
+
+ ```elixir
+ gray_data = <<128, 64, 32, 16>> # 4 gray pixels
+ {:ok, gray_image} = Image.new_from_binary(gray_data, 4, 1, 1, :VIPS_FORMAT_UCHAR)
+ ```
+
+ Creating an RGB image from raw pixel data:
+
+ pixel_data = get_rgb_pixels() # Binary of RGB values
+ {:ok, image} = Image.new_from_binary(pixel_data, 640, 480, 3, :VIPS_FORMAT_UCHAR)
+
+
+ For loading formatted binary (JPEG, PNG, etc) see `new_from_buffer/2`.
"""
@spec new_from_binary(
binary(),
@@ -563,34 +660,42 @@ defmodule Vix.Vips.Image do
end
@doc """
- Create a new image from Enumerable.
+ Creates a new image by lazily reading from an Enumerable source.
- Returns an image which will lazily pull data from passed
- Enumerable. `enum` should be stream of bytes of an encoded image
- such as JPEG. This functions recognizes the image format and
- metadata by reading starting bytes and wraps passed Enumerable as an
- image. Remaining bytes are read on-demand.
+ This function is ideal for processing large images without loading the entire file into memory.
+ It detects the image format from the initial bytes and reads remaining data on-demand.
- Useful when working with big images. Where you don't want to load
- complete input image data to memory.
+ ## Parameters
- ```elixir
- {:ok, image} =
- File.stream!("puppies.jpg", [], 1024) # or read from s3, web-request
- |> Image.new_from_enum()
+ * `enum` - An Enumerable producing image data (e.g., File.stream!, HTTP chunks)
+ * `opts` - Optional keyword list of format-specific options. To be backward compatible it also accepts options
+ as a string in "[name=value,...]" format for the time being.
- :ok = Image.write_to_file(image, "puppies.png")
- ```
+ ## Examples
- Optional param `opts` is passed to the image loader. Available
- options depends on the format.
+ Reading from a file stream:
- ```elixir
- Image.new_from_enum(stream, [shrink: 2])
- ```
+ {:ok, image} =
+ File.stream!("large_photo.jpg", [], 65_536)
+ |> Image.new_from_enum()
+
+ Reading from a file with options:
+
+ {:ok, image} =
+ File.stream!("large_photo.jpg", [], 65_536)
+ |> Image.new_from_enum(shrink: 2)
+
+ Processing S3 stream:
+
+ {:ok, image} =
+ ExAws.S3.download_file("bucket", "image.jpg")
+ |> Stream.map(&process_chunk/1)
+ |> Image.new_from_enum()
+
+ ## Format Options
+
+ To see format-specific options, check [Operation](./search.html?q=load+-buffer+-filename+-profile) module.
- You can find all options available for a format under operation function in
- [Operation](./search.html?q=load+-buffer+-filename+-profile) module.
"""
@spec new_from_enum(Enumerable.t(), String.t() | keyword) :: {:ok, t()} | {:error, term()}
def new_from_enum(enum, opts \\ []) do
@@ -634,31 +739,47 @@ defmodule Vix.Vips.Image do
end
@doc """
- Creates a Stream from Image.
+ Creates a Stream that lazily writes image data in the specified format.
- Returns a Stream which will lazily pull data from passed image.
+ This function is particularly useful for handling large images or when streaming
+ directly to storage/network without intermediate files.
- Useful when working with big images. Where you don't want to keep
- complete output image in memory.
+ ## Parameters
+ * `image` - The source image to stream
+ * `suffix` - Output format suffix. (e.g., ".jpg", ".png")
+ * `opts` - Optional keyword list of format-specific options (e.g., `[Q: 90]`)
- ```elixir
- {:ok, image} = Image.new_from_file("puppies.jpg")
+ ## Examples
- :ok =
- Image.write_to_stream(image, ".png")
- |> Stream.into(File.stream!("puppies.png")) # or write to S3, web-request
- |> Stream.run()
- ```
+ Basic streaming to file:
+
+ {:ok, image} = Image.new_from_file("input.jpg")
+
+ :ok =
+ Image.write_to_stream(image, ".png")
+ |> Stream.into(File.stream!("output.png"))
+ |> Stream.run()
+
+ Streaming with quality options:
+
+ :ok =
+ Image.write_to_stream(image, ".jpg", Q: 90, strip: true)
+ |> Stream.into(File.stream!("output.jpg"))
+ |> Stream.run()
- Optional param `opts` is passed to the image saver. Available
- options depends on the file format. You can find all options
- available for a format under operation function in
+ Streaming to S3:
+
+ :ok =
+ Image.write_to_stream(image, ".png")
+ |> Stream.each(&upload_chunk_to_s3/1)
+ |> Stream.run()
+
+ ## Format Options
+
+ Each format supports different saving options. View available options in
[Operation](./search.html?q=save+buffer+-filename+-profile) module.
- ```elixir
- Image.write_to_stream(vips_image, ".jpg", Q: 90)
- ```
"""
@spec write_to_stream(t(), String.t(), keyword) :: Enumerable.t()
@@ -775,26 +896,44 @@ defmodule Vix.Vips.Image do
end
@doc """
- Write `t:Vix.Vips.Image.t/0` to a file.
+ Writes a VIPS image to a file in the format determined by the file extension.
- The image format is selected based on image extension in `path`.
+ ## Parameters
- Optional param `opts` is passed to the image saver. Available
- options depends on the file format. You can find all options
- available for a format under operation function in
- [Operation](./search.html?q=save+-buffer+-filename+-profile) module.
+ * `image` - The source `t:Vix.Vips.Image.t/0` to save
+ * `path` - Destination file path (format determined by extension)
+ * `opts` - Format-specific saving options
- For example, you can find all of the options supported by JPEG saver
- undre `Vix.Vips.Operation.jpegsave/3` function documentation.
+ ## Format Options
- ```elixir
- # save with Quality set to 90
- Image.write_to_file(vips_image, "fred.jpg", Q: 90)
- ```
+ Each format supports different saving options, which can be found in the
+ [Operation](./search.html?q=save+-buffer+-filename+-profile) module documentation.
+
+ ## Examples
+
+ Basic usage:
+
+ :ok = Image.write_to_file(image, "output.jpg")
+
+ Saving with quality settings:
+
+ # JPEG with 90% quality
+ :ok = Image.write_to_file(image, "output.jpg", Q: 90)
+
+ # PNG with maximum compression
+ :ok = Image.write_to_file(image, "output.png", compression: 9)
+
+ Saving with multiple options:
+
+ # JPEG with quality and metadata stripping
+ :ok = Image.write_to_file(image, "output.jpg", Q: 90, strip: true)
+
+ ## Advanced Usage
- If you want more control over the saver, Use specific format saver
- from `Vix.Vips.Operation`. For example for jpeg use
- `Vix.Vips.Operation.jpegsave/2`
+ For more control, use format-specific savers from `Vix.Vips.Operation`:
+
+ # Using specific JPEG saver
+ :ok = Vix.Vips.Operation.jpegsave(image, "output.jpg", Q: 95)
"""
@spec write_to_file(t(), String.t(), keyword) :: :ok | {:error, term()}
@@ -815,27 +954,47 @@ defmodule Vix.Vips.Image do
end
@doc """
- Returns `t:Vix.Vips.Image.t/0` as a binary based on the format specified by `suffix`.
+ Converts a VIPS image to a binary representation in the specified format.
- This function is similar to `write_to_file` but instead of writing
- the output to the file, it returns it as a binary.
+ This function is similar to `write_to_file/3` but returns the encoded image
+ as a binary instead of writing to a file. This is particularly useful for
+ web applications or when working with in-memory image processing pipelines.
- Optional param `opts` is passed to the image saver. Available
- options depends on the file format. You can find all options
- available for a format under operation function in
- [Operation](./search.html?q=save+buffer+-filename+-profile) module.
+ ## Parameters
- For example, you can find all of the options supported by JPEG saver
- undre `Vix.Vips.Operation.jpegsave_buffer/2` function documentation.
+ * `image` - The source `t:Vix.Vips.Image.t/0` to convert
+ * `suffix` - Format extension (e.g., ".jpg", ".png")
+ * `opts` - Format-specific encoding options
- ```elixir
- # returns image in JPEG format as binary with Q factor set 90
- Image.write_to_buffer(img, ".jpg", Q: 90)
- ```
+ ## Examples
+
+ Basic conversion to different formats:
+
+ # Convert to JPEG binary
+ {:ok, jpeg_binary} = Image.write_to_buffer(image, ".jpg")
+
+ # Convert to PNG binary
+ {:ok, png_binary} = Image.write_to_buffer(image, ".png")
+
+ Converting with quality settings:
+
+ # JPEG with 90% quality
+ {:ok, jpeg_binary} = Image.write_to_buffer(image, ".jpg", Q: 90)
+
+ # PNG with maximum compression
+ {:ok, png_binary} = Image.write_to_buffer(image, ".png", compression: 9)
+
+ Web application example:
+
+ def show_image(conn, %{"id" => id}) do
+ image = MyApp.get_image!(id)
+ {:ok, binary} = Image.write_to_buffer(image, ".jpg", Q: 85)
+
+ conn
+ |> put_resp_content_type("image/jpeg")
+ |> send_resp(200, binary)
+ end
- If you want more control over the saver, Use specific format saver
- from `Vix.Vips.Operation`. For example for jpeg use
- `Vix.Vips.Operation.jpegsave_buffer/2`
"""
@spec write_to_buffer(t(), String.t(), keyword) :: {:ok, binary()} | {:error, term()}
@@ -852,37 +1011,54 @@ defmodule Vix.Vips.Image do
end
@doc """
- Returns raw pixel data of the image as `Vix.Tensor`
+ Extracts raw pixel data from a VIPS image as a `Vix.Tensor` structure.
- VIPS images are three-dimensional arrays, the dimensions being
- width, height and bands.
+ This function provides access to the underlying pixel data in a format suitable
+ for interoperability with other image processing or machine learning libraries.
- Each dimension can be up to 2 ** 31 pixels (or band elements).
- An image has a format, meaning the machine number type used to
- represent each value. VIPS supports 10 formats, from 8-bit unsigned
- integer up to 128-bit double complex.
+ ## Image Structure
- In VIPS, images are uninterpreted arrays, meaning that from
- the point of view of most operations, they are just large
- collections of numbers. There's no difference between an RGBA
- (RGB with alpha) image and a CMYK image, for example, they are
- both just four-band images.
+ VIPS images are three-dimensional arrays with the following dimensions:
+ * Width: The horizontal size (up to 2^31 pixels)
+ * Height: The vertical size (up to 2^31 pixels)
+ * Bands: The number of channels per pixel (e.g., 3 for RGB, 4 for RGBA)
- This function is intended to support interoperability of image
- data between different libraries. Since the array is created as
- a NIF resource it will be correctly garbage collected when
- the last reference falls out of scope.
+ ## Data Format
- Libvips might run all the operations to produce the pixel data
- depending on the caching mechanism and how image is built.
+ VIPS supports 10 different numeric formats for pixel values, ranging from
+ 8-bit unsigned integers to 128-bit double complex numbers. Images are treated
+ as uninterpreted arrays of numbers - there's no inherent difference between
+ different color spaces with the same number of bands (e.g., RGBA vs CMYK).
- ## Endianness
+ ## Performance Notes
- Returned binary term will be in native endianness. By default
- bitstring treats byte order as `big` endian which might *not* be
- native. Always use `native` specifier to ensure. See [Elixir
- docs](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#%3C%3C%3E%3E/1-endianness)
- for more details.
+ Depending on the caching mechanism and image construction, VIPS may need to run all
+ the operations in the pipeline to produce the pixel data.
+
+ ## Endianness Considerations
+
+ The binary data in the tensor uses native endianness. When processing this
+ data using bitstring syntax, always specify the `native` modifier:
+
+ # Correct - using native endianness
+ <>
+
+ # Incorrect - default big endian
+ <>
+
+ See [Elixir docs](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#%3C%3C%3E%3E/1-endianness) for more details.
+
+ ## Examples
+
+ Converting an image to a tensor:
+
+ {:ok, tensor} = Image.write_to_tensor(rgb_image)
+ %Vix.Tensor{
+ data: <>,
+ shape: {height, width, 3},
+ names: [:height, :width, :bands],
+ type: :u8
+ } = tensor
"""
@spec write_to_tensor(t()) :: {:ok, Vix.Tensor.t()} | {:error, term()}
@@ -900,14 +1076,28 @@ defmodule Vix.Vips.Image do
end
@doc """
- Returns raw pixel data of the image as binary term
+ Extracts raw pixel data from a VIPS image as a binary term.
+
+ This is a lower-level alternative to `write_to_tensor/1` that returns only the
+ raw binary data without the associated metadata. It's primarily intended for
+ cases where you already know the image dimensions and format.
+
+ ## Warning
+
+ It's recommended to use `write_to_tensor/1` instead of this function unless you
+ have a specific need for the raw binary data and already know:
+
+ * Image dimensions (height × width)
+ * Number of bands
+ * Pixel data format
+ * Data layout and organization
+
+ ## Examples
+
+ Extracting raw binary data:
- Please check `write_to_tensor` for more details. This function just
- returns the data instead of the `Vix.Tensor` struct.
+ {:ok, binary_data} = Image.write_to_binary(image)
- Prefer using `write_to_tensor` instead of this function. This is
- only useful if you already know the details about the returned
- binary blob. Such as height, width and bands.
"""
@spec write_to_binary(t()) :: {:ok, binary()} | {:error, term()}
def write_to_binary(image) do
diff --git a/lib/vix/vips/operation.ex b/lib/vix/vips/operation.ex
index 268ce5b..1110bd6 100644
--- a/lib/vix/vips/operation.ex
+++ b/lib/vix/vips/operation.ex
@@ -1,14 +1,95 @@
defmodule Vix.Vips.Operation do
@moduledoc """
- Vips Operations
+ Provides access to VIPS operations for image processing.
- See libvips
- [documentation](https://libvips.github.io/libvips/API/current/func-list.html)
- for more detailed description of the operation.
+ This module exposes VIPS operations as Elixir functions, allowing you to perform
+ various image processing tasks like resizing, color manipulation, filtering,
+ and format conversion.
+
+ ## Quick Start
+
+ Here's a simple example to resize an image:
+
+ # Load and resize an image to 500px width, maintaining aspect ratio
+ {:ok, image} = Operation.thumbnail("input.jpg", 500)
+
+ ## Working with Operations
+
+ Operations in Vix can be grouped into several categories:
+
+ * **Loading/Saving** - `Vix.Vips.Image`, `thumbnail/2`, and format specific functions.
+ * **Resizing** - `resize/2`, `thumbnail/2`, `smartcrop/3`
+ * **Color Management** - `colourspace/2`, `icc_transform/2`
+ * **Filters & Effects** - `gaussblur/2`, `sharpen/2`
+ * **Composition** - `composite/3`, `join/3`, `insert/4`
+
+ Most operations follow a consistent pattern:
+
+ 1. Load your image
+ 2. Apply one or more operations
+ 3. Save the result
+
+ ## Common Examples
+
+ # Basic image resizing while preserving aspect ratio
+ {:ok, image} = Vix.Vips.Image.new_from_file("input.jpg")
+ # scale down by 50%
+ {:ok, resized} = Operation.resize(image, scale: 0.5)
+ :ok = Vix.Vips.Image.write_to_file(resized, "output.jpg")
+
+ # Convert to grayscale and apply Gaussian blur
+ {:ok, image} = Vix.Vips.Image.new_from_file("input.jpg")
+ {:ok, gray} = Operation.colourspace(image, :VIPS_INTERPRETATION_B_W)
+ {:ok, blurred} = Operation.gaussblur(gray, 3.0)
+
+ ## Advanced Usage
+
+ ### Smart Cropping for Thumbnails
+
+ # Generate a smart-cropped thumbnail focusing on interesting areas
+ {:ok, thumb} = Operation.thumbnail("input.jpg", 300,
+ crop: :attention, # Uses image analysis to find interesting areas
+ height: 300, # Force square thumbnail
+ )
+
+ ### Complex Image Composition
+
+ # Create a watermarked image with transparency
+ {:ok, base} = Vix.Vips.Image.new_from_file("photo.jpg")
+ {:ok, watermark} = Vix.Vips.Image.new_from_file("watermark.png")
+ {:ok, composed} = Operation.composite2(base, watermark,
+ :VIPS_BLEND_MODE_OVER, # Blend mode
+ x: 20, # Offset from left
+ y: 20, # Offset from top
+ opacity: 0.8 # Watermark transparency
+ )
+
+ ### Color Management
+
+ # Convert between color spaces with ICC profiles
+ {:ok, image} = Vix.Vips.Image.new_from_file("input.jpg")
+ {:ok, converted} = Operation.icc_transform(image,
+ "sRGB.icc", # Target color profile
+ "input-profile": "Adobe-RGB.icc"
+ )
+
+
+ > ## Performance Tips {: .tip}
+ >
+ > * Use `thumbnail/2` instead of `resize/2` when possible - it's optimized for common cases
+ > * Chain operations to avoid intermediate file I/O
+ > * For batch processing, reuse loaded ICC profiles and watermarks
+ > * Consider using sequential mode for large images
+
+ ## Additional Resources
+
+ * [VIPS Documentation](https://www.libvips.org/API/current/)
+
+
+
+
+
- Vips operation functions are generated using vips-introspection and
- are up-to-date with libvips version installed. Documentation in the
- hexdocs might *not* match for you.
"""
import Vix.Vips.Operation.Helper