Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update documentation #189

Merged
merged 3 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
273 changes: 122 additions & 151 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,199 +4,170 @@
[![Hex.pm](https://img.shields.io/hexpm/v/vix.svg)](https://hex.pm/packages/vix)
[![docs](https://img.shields.io/badge/docs-hexpm-blue.svg)](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.

[![Run in Livebook](https://livebook.dev/badge/v1/blue.svg)](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
<!-- add before & after -->

# 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(<b>Vix</b> is <span foreground="red">awesome!</span>), 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()
```

<!-- TODO: Would be great to add examples for: -->
<!-- - Watermarking -->
<!-- - Image composition -->
<!-- - Batch processing -->
<!-- - Text overlay -->

## 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:

[![Run in Livebook](https://livebook.dev/badge/v1/blue.svg)](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
```

[![Run in Livebook](https://livebook.dev/badge/v1/blue.svg)](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.

[![Run in Livebook](https://livebook.dev/badge/v1/blue.svg)](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.
Loading