Skip to content

Releases: bbrks/go-blurhash

v1.2.0

30 Jan 01:20
07a73a7

Choose a tag to compare

Hello people! It's been a while...

I've applied some very long-overdue TLC to this library and have some great news for anybody using this in the real-world. The old performance was so embarrassingly bad I'm surprised it was even usable. The new version very much is production-ready and much, much quicker.


v1.2.0 brings significant performance improvements and greatly reduced memory usage, along with a set of alloc-friendly Decoder/Encoder APIs, allowing efficient reuse of buffers for large batch jobs or long-running services.

Performance Highlights

Operation Improvement
Encode ~50-140x faster (41ms → 829µs and 75ms → 534µs)
Decode ~11x faster (332µs → 30µs)
Encode memory 99.4% reduction (3MB → 14KB)
Encode allocations 500,000 → 6 per operation

Reusable Encoder/Decoder APIs

New Encoder and Decoder types allow reusing internal buffers across multiple operations, allowing for near zero-alloc (amortized) batch processing:

enc := blurhash.NewEncoder()
for _, img := range images {
    hash, _ := enc.Encode(3, 4, img)
}

dec := blurhash.NewDecoder()
for _, hash := range hashes {
    img, _ := dec.Decode(hash, 128, 128, 1)
}

Other Changes

  • A little modernization/cleanup for now widely available Go features
  • Removed the only dependency this library had, which was test-only anyway
  • Added fuzz testing (and found a few bugs with it!)

Benchmarks

benchstat v1.1.1...v1.2.0 (click to expand)
goos: linux
goarch: amd64
pkg: github.com/bbrks/go-blurhash
cpu: AMD Ryzen 7 7800X3D 8-Core Processor           
                                                                           │ bench-v1.1.1.txt │          bench-v1.2.0.txt           │
                                                                           │      sec/op      │   sec/op     vs base                │
Components/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                        8.511n ± 1%   5.570n ± 1%  -34.56% (p=0.000 n=10)
Components/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                        8.425n ± 1%   5.507n ± 2%  -34.63% (p=0.000 n=10)
Components/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                        8.418n ± 1%   5.485n ± 2%  -34.85% (p=0.000 n=10)
Components/KJG8_@Dgx]_4V?xuyE%NRj-16                                              8.406n ± 1%   5.557n ± 2%  -33.90% (p=0.000 n=10)
Decode/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                           332.56µ ± 1%   29.69µ ± 1%  -91.07% (p=0.000 n=10)
Decode/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                           301.43µ ± 1%   30.25µ ± 1%  -89.97% (p=0.000 n=10)
Decode/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                           332.42µ ± 1%   29.73µ ± 1%  -91.06% (p=0.000 n=10)
Decode/KJG8_@Dgx]_4V?xuyE%NRj-16                                                 288.01µ ± 0%   24.39µ ± 1%  -91.53% (p=0.000 n=10)
DecodeDraw/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                       329.46µ ± 1%   28.56µ ± 1%  -91.33% (p=0.000 n=10)
DecodeDraw/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                       300.15µ ± 0%   28.89µ ± 0%  -90.37% (p=0.000 n=10)
DecodeDraw/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                       332.43µ ± 1%   28.56µ ± 2%  -91.41% (p=0.000 n=10)
DecodeDraw/KJG8_@Dgx]_4V?xuyE%NRj-16                                             287.61µ ± 1%   23.24µ ± 1%  -91.92% (p=0.000 n=10)
Encode/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                          75498.7µ ± 1%   534.2µ ± 1%  -99.29% (p=0.000 n=10)
Encode/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                          41166.9µ ± 1%   829.3µ ± 3%  -97.99% (p=0.000 n=10)
Components/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                            5.570n ± 2%
Decode/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                                55.47µ ± 1%
DecodeDraw/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                            54.14µ ± 1%
DecoderReuse/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                                    29.05µ ± 1%
DecoderReuse/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                                    29.42µ ± 1%
DecoderReuse/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                          54.47µ ± 1%
DecoderReuse/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                                    28.90µ ± 1%
DecoderReuse/KJG8_@Dgx]_4V?xuyE%NRj-16                                                          23.86µ ± 1%
DecoderDrawReuse/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                                27.80µ ± 2%
DecoderDrawReuse/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                                27.96µ ± 1%
DecoderDrawReuse/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                      52.58µ ± 1%
DecoderDrawReuse/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                                27.73µ ± 1%
DecoderDrawReuse/KJG8_@Dgx]_4V?xuyE%NRj-16                                                      22.19µ ± 1%
Encode/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                                26.79m ± 4%
EncoderReuse/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                                    536.6µ ± 1%
EncoderReuse/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                                    814.4µ ± 3%
EncoderReuse/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                          26.87m ± 3%
geomean                                                                           32.44µ        17.85µ       -88.19%

                                                                           │ bench-v1.1.1.txt │            bench-v1.2.0.txt            │
                                                                           │       B/op       │     B/op      vs base                  │
Components/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                       0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
Components/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                       0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
Components/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                       0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
Components/KJG8_@Dgx]_4V?xuyE%NRj-16                                             0.000 ± 0%       0.000 ± 0%        ~ (p=1.000 n=10) ¹
Decode/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                         4.344Ki ± 0%     6.094Ki ± 0%  +40.29% (p=0.000 n=10)
Decode/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                         4.344Ki ± 0%     6.094Ki ± 0%  +40.29% (p=0.000 n=10)
Decode/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                         4.344Ki ± 0%     6.094Ki ± 0%  +40.29% (p=0.000 n=10)
Decode/KJG8_@Dgx]_4V?xuyE%NRj-16                                               4.281Ki ± 0%     5.781Ki ± 0%  +35.04% (p=0.000 n=10)
DecodeDraw/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                     4.344Ki ± 0%     2.031Ki ± 0%  -53.24% (p=0.000 n=10)
DecodeDraw/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                     4.344Ki ± 0%     2.031Ki ± 0%  -53.24% (p=0.000 n=10)
DecodeDraw/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                     4.344Ki ± 0%     2.031Ki ± 0%  -53.24% (p=0.000 n=10)
DecodeDraw/KJG8_@Dgx]_4V?xuyE%NRj-16                                           4.281Ki ± 0%     1.719Ki ± 0%  -59.85% (p=0.000 n=10)
Encode/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                       1951.34Ki ± 0%     11.96Ki ± 0%  -99.39% (p=0.000 n=10)
Encode/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                       3072.60Ki ± 0%     14.34Ki ± 0%  -99.53% (p=0.000 n=10)
Components/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                              0.000 ± 0%
Decode/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                                7.188Ki ± 0%
DecodeDraw/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                            3.125Ki ± 0%
DecoderReuse/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                                    4.062Ki ± 0%
DecoderReuse/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                                    4.062Ki ± 0%
DecoderReuse/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                          4.062Ki ± 0%
DecoderReuse/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                                    4.062Ki ± 0%
DecoderReuse/KJG8_@Dgx]_4V?xuyE%NRj-16                                                          4.062Ki ± 0%
DecoderDrawReuse/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                                  0.000 ± 0%
DecoderDrawReuse/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                                  0.000 ± 0%
DecoderDrawReuse/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                        0.000 ± 0%
DecoderDrawReuse/LNMF%n00%#MwS|WCWEM{R*bbWBbH-16                                                  0.000 ± 0%
DecoderDrawReuse/KJG8_@Dgx]_4V?xuyE%NRj-16                                                        0.000 ± 0%
Encode/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                                80.74Ki ± 0%
EncoderReuse/LFE.@D9F01_2%L%MIVD*9Goe-;WB-16                                                      61.00 ± 0%
EncoderReuse/LNAdApj[00aymkj[TKay9}ay-Sj[-16                                                      66.00 ± 2%
EncoderReuse/eaF#5R0#WBjYR+58-nWCWBn~bIsTbbayjFWof8jFj[WX-nNHR*jss.-16                          1.992Ki ± 7%
geomean                                                                                     ²                 -58.58%                ²
¹ a...
Read more

Simplify slice init to fix lint warning

02 Jan 16:49

Choose a tag to compare

v1.1.1

Simplify slice init to fix lint warning

DecodeDraw to support decoding hashes into any image type

01 Dec 13:28
a1611e5

Choose a tag to compare

You can decode blurhashes into any image type satisfying the image.Image interface by using the DecodeDraw function (#3)

v1.0

13 May 23:47

Choose a tag to compare

API stable

Decode implementation

09 May 00:33

Choose a tag to compare

Remove 1.13 error handling

Also added go.mod file