# Vix


Vix is Elixir extension for [vips]( image processing library.

### Why Vix

Vix is a **NIF** based bindings library for libvips. Vix does not spawn OS processes for the operations like other libraries. And it can make full use of libvips [optimizations]( such as joining of operations in the pipeline, cache etc.

Operation bindings are generated using vips introspection, so the generated documentation and bindings always matches the vips version installed.

Check [vips operation documentation]( for the list of available operations and spec.

### What is Vips

From vips documentation:

> libvips is a [demand-driven, horizontally threaded]( image processing library. Compared to similar libraries, [libvips runs quickly and uses little memory](

## Introduction

Easiest way to get started or to explore the operations is to run Introduction Livebook.

[![Run in Livebook](](

# print vips version
IO.puts("Version: " <> Vix.Vips.version())

# contains image read/write functions
alias Vix.Vips.Image

# reading image from a file. Note that image is not actually loaded to the memory at this point.
# img is `%Image{}` struct.
{:ok, img} = Image.new_from_file("~/Downloads/kitty.png")

# You can also load image from binary. This let us to work images without touching file system.
# It tires to guess image format from the binary and uses correct loader.

bin =!("~/Downloads/kitty.png")
{:ok, %Image{} = img} = Image.new_from_buffer(bin)

# If you know image format beforehand then you can use appropriate function from
# `Vix.Vips.Operation`. For example to load png you can use `Vix.Vips.Operation.pngload_buffer/2`.

bin =!("~/Downloads/kitty.png")
{:ok, {img, _flags}} = Vix.Vips.Operation.pngload_buffer(bin)

# writing `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 image dimensions
IO.puts("Width: #{Image.width(img)}")
IO.puts("Height: #{Image.height(img)}")

# Operations

# contains image processing operations
alias Vix.Vips.Operation

# getting a rectangular region from the image (crop)
{:ok, extract_img} = Operation.extract_area(img, 100, 50, 200, 200)

# create image thumbnail.
# this function accepts many optional parameters, see:
# also see `Operation.thumbnail/3` which accepts image path
{:ok, thumb} = Operation.thumbnail_image(img, 100)

# resize 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)

# flip image
{:ok, flipped_img} = Operation.flip(img, :VIPS_DIRECTION_HORIZONTAL)

# Gaussian blur
{:ok, blurred_img} = Operation.gaussblur(img, 5)

# convert image to a grayscale image
{:ok, bw_img} = Operation.colourspace(img, :VIPS_INTERPRETATION_B_W)

# adding gray border
{:ok, extended_img} =
  Operation.embed(img, 10, 10, Image.width(img) + 20, Image.height(img) + 20,
    background: [128]

# rotate image 90 degree clockwise
{:ok, rotated_img} = Operation.rot(img, :VIPS_ANGLE_D90)

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

# render text as image
# see 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)

## Creating GIF
black =!(500, 500, bands: 3)

# create images with different grayscale
frames =, fn n ->
  Operation.linear!(black, [1], [n,n,n])

{:ok, joined_img} = Operation.arrayjoin(frames, across: 1)

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

:ok = Operation.gifsave(joined_img, Path.expand("~/Downloads/bw.gif"), "page-height": 500)

The [libvips reference manual]( has more detailed documentation about the operations.

### Bonus

Livebook implementing picture language defined in [*Structural and Interpretation of Computer Programs*]( section [2.2.4](

[![Run in Livebook](](

### Warning

This library is experimental and the code is not well tested, so you might experience crashes.

### Requirements

* libvips with development headers
  * **macOS**: using brew `brew install libvips`
  * **Linux**: using deb `apt install libvips-dev`

  For more details see
* pkg-config
* c compiler

## Installation

def deps do
    {:vix, "~> x.x.x"}

### TODO
- [ ] support mutable operations such as draw*