A pure Elixir implementation Blurhash decoder/encoder.
Documentation: https://hexdocs.pm/rinpatch_blurhash
Add Blurhash to your mix.exs
:
def deps do
[
{:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash}
]
end
If you would like to use the downscale_and_decode/3
function, you also need to add Mogrify
:
def deps do
[
{:blurhash, "~> 0.1.0", hex: :rinpatch_blurhash},
{:mogrify, "~> 0.8.0"}
]
end
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)
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()