• Stars
    star
    114
  • Rank 296,484 (Top 7 %)
  • Language
    Elixir
  • License
    MIT License
  • Created over 3 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Elixir extension for libvips

Vix

CI Hex.pm docs

Vix is an Elixir extension for libvips image processing library.

About libvips from its documentation:

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

About Vix

Vix is a NIF based bindings library for libvips.

Major Features:

  • Vix can take full advantage of libvips optimizations, such as joining of operations in the pipeline, cache. Since Vix is native binding
  • Experimental support for streaming. User can read or write images without keeping 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, 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 you don't have to worry about bringing the libvips dependencies and compiling NIF. Just add vix and you are good to go! See below for more details
  • Ergonomic bindings with auto generated documentation for the operations using vips introspection. So they always match the libvips installed. If newer libvips update 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 for the list of available operations and spec.

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 use that for operation. This makes deployment and release of your application a breeze. With this you don't have to install any compiler tools or libvips to use Vix. But if you find that the pre-built NIF or libvips is missing some additional features or support for additional image format then you can bring your own libvips by installing it manually and ask 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 tiff support, vix will generate tiff related bindings for you.

You can choose this using VIX_COMPILATION_MODE env variable. This variable must be set both during compilation and runtime. Possible values are:

  • PRECOMPILED_NIF_AND_LIBVIPS (Default): Uses vix provided NIF and libvips. No need to install any additional dependencies. Big thanks to sharp library maintainers, pre-compiled libvips is based on: https://github.com/lovell/sharp-libvips/.

    Run this command below to generate the required checksum.exs file.

    MIX_ENV=dev mix elixir_make.checksum --all --ignore-unavailable
  • PLATFORM_PROVIDED_LIBVIPS: Uses platform provided libvips and NIF will be compiled during compilation phase. You need to install required build tools to compile NIF. To build NIF you need these:

    • libvips with development headers
    • pkg-config
    • C compiler

Should I use Vix or Image?

Vix is focused on bridging beam and libvips, and tries to be close to libvips interface to support large set of use cases. Because of this doing some basic operation might feel unintuitive. Image an excellent library by @kipcole9 builds on top of Vix and provides more elixir friendly wrapper functions for common operations along with many additional features such handling Exif, Math operators, and more. And all of this is accompanied by good documentation. So for most of the users, using Vix via Image might be better choice.

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 = File.read!("~/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 = File.read!("~/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 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)


# 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,
    extend: :VIPS_EXTEND_BACKGROUND,
    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 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)


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

# create images with different grayscale
frames = Enum.map(1..255//10, fn n ->
  Operation.linear!(black, [1], [n/255,n/255,n/255])
end)

{: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)
  end)

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

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

Livebooks

Run in Livebook

  • Creating Rainbow. Quick introduction to complex number and operations, mapim, buildlut.

Run in Livebook

  • Auto correct Document Rotation. Quick introduction to Fourier Transformation, Complex planes, and Arithmetic Operations.

Run in Livebook

NIF Error Logging

Vix NIF code writes logs to stderr on certain errors. This is disabled by default. To enable logging set VIX_LOG_ERROR environment variable to true.

Installation

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

More Repositories

1

exile

Alternative to ports for running external programs. It provides back-pressure, non-blocking io, and solves port related issues
Elixir
105
star
2

ex_cmd

ExCmd is an Elixir library to run external programs and to communicate with back pressure
Elixir
49
star
3

off_broadway_redis_stream

A Broadway producer for Redis Stream
Elixir
16
star
4

unzip

Module to get files out of a zip
Elixir
15
star
5

eglot-flycheck-adaptor

Replaces flymake with flycheck for eglot diagnostics
Emacs Lisp
10
star
6

odu

Middleware program which helps with talking to external programs from Elixir or Erlang.
Go
10
star
7

ex_mustache

Efficient Mustache templates for Elixir
HTML
4
star
8

exscheme

Toy Scheme implementation in Elixir inspired by SICP
Elixir
3
star
9

zero_copy

Demo of sharing binary to and from NIF without copying
C
2
star
10

kino_vix

Vix integrations for Livebook
Elixir
2
star
11

dmenu-unicode

Unicode with ligature (glyphs) support for dmenu using Pango library.
C
2
star
12

slice-mp3

Simple mp3 cutter and data reader
C++
2
star
13

akash-akya.github.io

HTML
2
star
14

sublime-word-movement

Simple Sublime Text like word movement for Emacs
Emacs Lisp
1
star
15

resty.el

WIP: Programmable emacs interface to interact with RESTful endpoints
Emacs Lisp
1
star
16

2048-lisp

2048
Common Lisp
1
star
17

dasa-pada

Java
1
star
18

vachana-app

Java
1
star
19

exdot

Elixir abstraction for generating Graphviz dot formatted string
Elixir
1
star
20

openapi-diff

fork of https://bitbucket.org/atlassian/openapi-diff
TypeScript
1
star
21

xkcd-app

A simple android application for xkcd comics.
Java
1
star
22

external_display_watcher

Mac OS command-line utility to watch for external display connectivity
Objective-C
1
star
23

json-schema-diff

fork of https://bitbucket.org/atlassian/json-schema-diff
TypeScript
1
star