Consider using my blurhash library
A while ago I wrote a pure Elixir implementation of the Blurhash algorithm. And I think there are several reasons why it should replace the currently used eblurhash
library in Pleroma.
Pros:
- There is no need for an external C program to handle the encoding.
eblurhash
uses a C program in a subprocess which also includes a 10k line image processing header library, which does make it less reliable in theory. By contrast, my library doesn't use anything except imagemagick, also used byeblurhash
. - It's faster. I am not particularly sure of the reason for that, but my library appears to be 4 times faster judging from multiple Benchee runs. That is despite the fact my libary downscales images to 32 pixels in width before running the algorithm, whereas
eblurhash
downscales it to 20.
iex(6)> Benchee.run(%{"elixir blurhash" => fn -> Blurhash.downscale_and_encode("avatar.jpg", 4, 4) end, "eblurhash" => fn -> :eblurhash.magick("avatar.jpg") end}, memory_time: 4)
Operating System: Linux
CPU Information: AMD Ryzen 9 3950X 16-Core Processor
Number of Available Cores: 32
Available memory: 31.32 GB
Elixir 1.12.2
Erlang 24.1.2
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 4 s
parallel: 1
inputs: none specified
Estimated total run time: 22 s
Benchmarking eblurhash...
Benchmarking elixir blurhash...
Name ips average deviation median 99th %
elixir blurhash 27.47 36.40 ms ±6.72% 36.89 ms 41.24 ms
eblurhash 6.13 163.15 ms ±2.12% 162.53 ms 178.31 ms
Comparison:
elixir blurhash 27.47
eblurhash 6.13 - 4.48x slower +126.75 ms
- It's almost a drop-in replacement. Just replace
:eblurhash.magick(file)
withBlurhash.downscale_and_encode(file, 4, 4)
after adding the dependency.
Cons:
- It potentially uses more memory. The part I left out from the benchmark above:
Memory usage statistics:
Name average deviation median 99th %
elixir blurhash 5.78 MB ±0.00% 5.78 MB 5.78 MB
eblurhash 0.0723 MB ±0.52% 0.0725 MB 0.0725 MB
Comparison:
elixir blurhash 5.78 MB
eblurhash 0.0723 MB - 0.01x memory usage -5.70750 MB
Now, this is unfrair because eblurhash
does all of it's work in a C subprocess. So let's measure memory usage of that:
~/s/pleroma % /usr/bin/time -v ./deps/eblurhash/priv/blurhash 4 4 avatar_thumb.gif
UVIN2gkV0Ljc9bNGxuofMxW.-ps:-=xaIUR*
[...]
Maximum resident set size (kbytes): 1400
[...]
Note that this is still not a completely fair comparison, but let's assume that in the worst case the Elixir library uses 4 times more memory.
- It doesn't calculate blurhash components based on width and height like
eblurhash
does. I do not think this is an issue since Mastodon actually hardcodes 4x4 components, but if for some reason this behavior is something we want to keep, this will need to be implemented.
cc @alexgleason since he implemented blurhash in Pleroma
Edited by rinpatch