Packages
image
0.54.2
0.72.0
0.71.0
0.70.0
0.69.0
0.68.0
0.67.0
0.67.0-dev
retired
0.66.0
0.65.0
0.64.0
0.63.0
0.62.1
0.62.0
0.61.1
0.61.0
0.60.0
0.59.3
0.59.2
0.59.1
0.59.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.2
0.55.1
retired
0.55.0
0.54.4
0.54.3
0.54.2
0.54.1
0.54.0
0.53.0
0.52.3
0.52.2
0.52.1
0.52.0
retired
0.51.0
0.50.0
0.49.0
0.48.1
0.48.0
0.47.0
0.46.0
0.45.0
0.44.0
0.43.2
0.43.1
0.43.0
0.42.0
0.41.0
0.40.0
0.39.3
0.39.2
0.39.1
0.39.0
0.38.4
0.38.3
0.38.2
0.38.1
0.38.0
0.37.0
0.36.2
0.36.1
0.36.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.1
0.31.0
0.30.0
0.29.0
0.28.2
0.28.1
0.28.0
0.27.0
0.26.0
0.25.1
0.25.0
0.24.1
0.24.0
0.23.2
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
retired
0.19.0
0.18.1
0.18.0
0.17.0
0.16.0
0.15.0
0.14.4
0.14.2
0.14.1
0.14.0
retired
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.10.0-rc.0
retired
0.9.0
retired
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
An approachable image processing library primarily based upon Vix and libvips that is NIF-based, fast, multi-threaded, pipelined and has a low memory footprint.
Current section
Files
Jump to
Current section
Files
lib/image/blurhash/encoder.ex
defmodule Image.Blurhash.Encoder do
@moduledoc false
import Image.Blurhash.Utils
alias Image.Blurhash.Base83
import Bitwise
def encode(pixels, width, height, components_x, components_y) do
components = calculate_components(pixels, components_x, components_y, width, height)
{:ok, encode_blurhash(components, components_x, components_y)}
end
defp encode_blurhash([dc | ac], x, y) do
size_flag = encode_size_flag(x, y)
dc = encode_dc(dc)
{max_ac, ac} = encode_ac(ac)
size_flag <> max_ac <> dc <> ac
end
defp calculate_component(pixels, component_x, component_y, width, height, acc \\ {{0, 0, 0}, 0})
defp calculate_component(
<<r::8, g::8, b::8, rest::binary>>,
component_x,
component_y,
width,
height,
{{acc_r, acc_g, acc_b}, index}
) do
pixel_x = rem(index, width)
pixel_y = floor(index / width)
# DC
normalization_factor =
unless component_x == 0 and component_y == 0,
do: 2,
else: 1
basis =
normalization_factor * :math.cos(:math.pi() * pixel_x * component_x / width) *
:math.cos(:math.pi() * pixel_y * component_y / height)
linear_r = srgb_to_linear(r)
linear_g = srgb_to_linear(g)
linear_b = srgb_to_linear(b)
acc_r = acc_r + basis * linear_r
acc_g = acc_g + basis * linear_g
acc_b = acc_b + basis * linear_b
acc = {{acc_r, acc_g, acc_b}, index + 1}
calculate_component(rest, component_x, component_y, width, height, acc)
end
defp calculate_component(_, _, _, width, height, {{r, g, b}, _}) do
scale = 1 / (width * height)
{r * scale, g * scale, b * scale}
end
defp calculate_components(pixels, x, y, width, height) do
for y <- 0..(y - 1),
x <- 0..(x - 1) do
{{x, y}, calculate_component(pixels, x, y, width, height)}
end
end
defp encode_size_flag(x, y) do
Base83.encode_number(x - 1 + (y - 1) * 9, 1)
end
defp encode_dc({_, {linear_r, linear_g, linear_b}}) do
r = linear_to_srgb(linear_r)
g = linear_to_srgb(linear_g)
b = linear_to_srgb(linear_b)
Base83.encode_number(bsl(r, 16) + bsl(g, 8) + b, 4)
end
defp encode_ac([]) do
{Base83.encode_number(0, 1), ""}
end
defp encode_ac(ac) do
max_ac = Enum.reduce(ac, -2, fn {_, {r, g, b}}, max_ac -> Enum.max([max_ac, r, g, b]) end)
quantized_max_ac = floor(max(0, min(82, floor(max_ac * 166 - 0.5))))
max_ac_for_quantization = (quantized_max_ac + 1) / 166
encoded_max_ac = Base83.encode_number(quantized_max_ac, 1)
encoded_components =
Enum.reduce(ac, "", fn {_, {r, g, b}}, hash ->
r = quantize_color(r, max_ac_for_quantization)
g = quantize_color(g, max_ac_for_quantization)
b = quantize_color(b, max_ac_for_quantization)
hash <> Base83.encode_number(r * 19 * 19 + g * 19 + b, 2)
end)
{encoded_max_ac, encoded_components}
end
end