View Source Introduction
install-dependencies
Install dependencies
Mix.install([
{:kino, "~> 0.3.0"},
{:vix, "~> 0.5"}
])
# print vips version
IO.puts("Version: " <> Vix.Vips.version())
vips-image
Vips Image
All image IO operations such as reading and writing files are available in Vix.Vips.Image
module. Image module also contains functions get image attributes. Most Vips operations takes %Vix.Vips.Image{}
instance
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, %Image{} = 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)}")
Kino supports showing image inline. We can use this to display image in the livebook. This opens gate for exploratory image processing
defmodule VixExt do
alias Vix.Vips.Operation
@max_height 500
def show(%Image{} = image) do
height = Image.height(image)
# scale down if image height is larger than 500px
image =
if height > @max_height do
Operation.resize!(image, @max_height / height)
else
image
end
# write vips-image as png image to memory
{:ok, image_bin} = Image.write_to_buffer(image, ".png")
Kino.render(Kino.Image.new(image_bin, "image/png"))
:ok
end
end
import VixExt
# Lets see show in action
show(img)
vips-operations
Vips Operations
All image processing operations are available in Vix.Vips.Operation
alias Vix.Vips.Operation
crop
Crop
Getting a rectangular region from the image
{:ok, extract_img} = Operation.extract_area(img, 100, 50, 200, 200)
show(extract_img)
thumbnail
Thumbnail.
This function accepts many optional parameters, see vips thumbnail doc for more details.
Also see Operation.thumbnail/3
which accepts image path
{:ok, thumb} = Operation.thumbnail_image(img, 100)
show(thumb)
resize
Resize
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)
show(resized_img)
flip
Flip
direction =
case IO.gets("Direction: ") do
"horizontal\n" -> :VIPS_DIRECTION_HORIZONTAL
"vertical\n" -> :VIPS_DIRECTION_VERTICAL
end
{:ok, flipped_img} = Operation.flip(img, direction)
show(flipped_img)
text
Text
Text operation takes multiple optional parameters. See libvips doc for more details
str = String.trim(IO.gets("Text: "))
{:ok, {text, _}} = Operation.text(str, dpi: 300, rgba: true)
# add text to an image
{:ok, inserted_text_img} = Operation.composite2(img, text, :VIPS_BLEND_MODE_OVER, x: 50, y: 20)
show(inserted_text_img)
creating-gif
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,n,n])
end)
{:ok, joined_img} = Operation.arrayjoin(frames, across: 1)
{: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)
few-more-operations
Few more operations
# Gaussian blur
{:ok, blurred_img} = Operation.gaussblur(img, 5)
show(blurred_img)
# convert image to a grayscale image
{:ok, bw_img} = Operation.colourspace(img, :VIPS_INTERPRETATION_B_W)
show(bw_img)
# 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]
)
show(extended_img)
# rotate image 90 degree clockwise
{:ok, rotated_img} = Operation.rot(img, :VIPS_ANGLE_D90)
show(rotated_img)
# 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)
show(joined_img)