Blurhash (blurhash v0.1.0)

Blurhash

A pure Elixir implementation Blurhash decoder/encoder.

Documentation: https://hexdocs.pm/rinpatch_blurhash

Installation

Add Blurhash to your mix.exs:

def deps do
  [
    {:rinpatch_blurhash, "~> 0.1.0"}
  ]
end

If you would like to use the downscale_and_decode/3 function, you also need to add Mogrify:

def deps do
  [
    {:rinpatch_blurhash, "~> 0.1.0"},
    {:mogrify, "~> 0.8.0"}
  ]
end

Usage

Encoding

The algorithm authors recommend to downscale the image to 32-20 pixels in width before encoding the blurhash, this will make encoding faster while leading to a similar-looking result. If ImageMagick is available on your system, you can simply add Mogrify package to your dependencies and use downscale_and_encode/3:

path = "/tmp/lenna.png"
components_x = 4
components_y = 3

{:ok, blurhash} = Blurhash.downscale_and_encode(path, components_x, components_y)

Be aware that this function uses a port and has no rate limiting or pooling. If a large number of blurhashes needs to be encoded at the same time, use an external solution to limit it, such as a job queue.

If you already have a thumbnail to encode to a blurhash, the encode/5 function accepts a raw 8-bit RGB binary along with it's width and height.

Here is how to convert an image to raw pixels using imagemagick:

convert lenna.png -depth 8 lenna.rgb

Then you can use it like this:

lenna = File.read!("lenna.rgb")
width = 512
height = 512
components_x = 4
components_y = 3

{:ok, blurhash} = Blurhash.encode(lenna, width, height, 4, 3)

Decoding

The decode/3 functions accepts a blurhash, as well as the width and height of the result image. The output is 8-bit raw RGB binary and the average colour of the image as an {r, g, b} tuple.

For example, decoding a blurhash to a 32x32 image:

blurhash = "LELxMqDQNE}@^5=aR6N^v}ozEh-n"
width = 32
height = 32

{:ok, pixels, {r, g, b} = average_color} = Blurhash.decode(blurhash, width, height)

decode_to_iodata/3 function is the same as decode/3, except it returns iodata instead of a binary. This is useful if you are writing the raw pixels to a file or a socket later.

For example, decoding a blurhash, writing the raw pixels to a file and converting it to a jpg using Mogrify:

blurhash = "LELxMqDQNE}@^5=aR6N^v}ozEh-n"
width = 32
height = 32

{:ok, pixels_iodata, {r, g, b} = average_color} = Blurhash.decode(blurhash, width, height)

decoded_raw_path = "lenna_blurhash.rgb"
File.write!(decoded_raw_path, pixels_iodata)

%{path: decoded_jpg_path} = 
  Mogrify.open(decoded_raw_path) |> Mogrify.custom("size", "#{width}x#{height}") |> Mogrify.custom("depth", "8")|> Mogrify.format("jpg") |> Mogrify.save()

Link to this section Summary

Functions

Decode a blurhash. Returns raw pixels (8bit RGB) and average color.

Same as decode/3, except returns pixels as iodata.

Downscale the image using &downscale_image/1 and encode a blurhash for it.

Downscale the image to 32 pixels wide and convert it to raw pixels, making it ready for Blurhash encoding. Returns path to image, width and height in case of success. Requires Mogrify package and ImageMagick to be installed on the system.`

Encodes a blurhash from raw pixels (8bit RGB).

Link to this section Types

Specs

blurhash() :: String.t()

Specs

color() :: {0..255, 0..255, 0..255}

Specs

pixels() :: <<_::8>>
Link to this type

pixels_iodata()

Specs

pixels_iodata() :: pixels() | [pixels() | pixels_iodata()]

Link to this section Functions

Link to this function

decode(blurhash, width, height)

Specs

decode(blurhash(), pos_integer(), pos_integer()) ::
  {:ok, pixels(), color()} | {:error, :unexpected_components | :unexpected_end}

Decode a blurhash. Returns raw pixels (8bit RGB) and average color.

Link to this function

decode_to_iodata(blurhash, width, height)

Specs

decode_to_iodata(String.t(), pos_integer(), pos_integer()) ::
  {:ok, pixels_iodata(), color()}
  | {:error, :unexpected_components | :unexpected_end}

Same as decode/3, except returns pixels as iodata.

Link to this function

downscale_and_encode(path, components_x, components_y)

Specs

downscale_and_encode(Path.t(), pos_integer(), pos_integer()) ::
  {:ok, blurhash()} | {:error, any()}

Downscale the image using &downscale_image/1 and encode a blurhash for it.

Link to this function

downscale_image(path)

Specs

downscale_image(Path.t()) ::
  {:ok, Path.t(), pos_integer(), pos_integer()} | {:error, any()}

Downscale the image to 32 pixels wide and convert it to raw pixels, making it ready for Blurhash encoding. Returns path to image, width and height in case of success. Requires Mogrify package and ImageMagick to be installed on the system.`

Link to this function

encode(pixels, width, height, components_x, components_y)

Specs

encode(pixels(), pos_integer(), pos_integer(), 1..9, 1..9) ::
  {:ok, blurhash()}
  | {:error, :too_many_components | :too_little_components | :malformed_pixels}

Encodes a blurhash from raw pixels (8bit RGB).