blurhash_ruby 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ef513fb805c4bdc62e5236843403bb3af8cb06c034c48ac2abc1a9d94a6863e8
4
+ data.tar.gz: 037752a9951af438c498f2caf27ab31f3717023124fa3c7e4300761cbb7f8c12
5
+ SHA512:
6
+ metadata.gz: 751b20bc24a4a36e0f97121e1faabef567afdf04e3c9e69763b121a6c7c5c4e9746eeba1b38ef266467109985752868c9b9b26ec5930e2f0afff4f43a9a97e93
7
+ data.tar.gz: 4b69c4baef24c4e7d696a818b92a6d04d685a01c1c6f8865a84ce31d6102ab2709113ea72070220a87be349c832cc9c2ee49efef8a4e6fd3d82b6380b66eb217
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ tmp
2
+ lib/blurhash_decoder/binary/*.bundle
3
+ lib/blurhash_encoder/binary/*.bundle
4
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rake-compiler"
data/Gemfile.lock ADDED
@@ -0,0 +1,15 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ rake (13.0.6)
5
+ rake-compiler (1.1.9)
6
+ rake
7
+
8
+ PLATFORMS
9
+ ruby
10
+
11
+ DEPENDENCIES
12
+ rake-compiler
13
+
14
+ BUNDLED WITH
15
+ 2.1.4
data/README.md ADDED
@@ -0,0 +1 @@
1
+ ## Blurhash Ruby
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "rake/extensiontask"
2
+
3
+ Rake::ExtensionTask.new "blurhash_decoder" do |ext|
4
+ ext.lib_dir = 'lib/blurhash_decoder/binary'
5
+ end
6
+
7
+ Rake::ExtensionTask.new "blurhash_encoder" do |ext|
8
+ ext.lib_dir = 'lib/blurhash_encoder/binary'
9
+ end
@@ -0,0 +1,17 @@
1
+ # lib = File.expand_path('../lib/', __FILE__)
2
+ # $:.unshift lib unless $:.include?(lib)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'blurhash_ruby'
6
+ s.version = '0.0.14'
7
+ s.summary = "A fast blurhash encoder/decoder gem!"
8
+ s.description = "A fast blurhash encoder/decoder gem."
9
+ s.authors = ["Rabin Poudyal"]
10
+ s.email = 'rabin@trip101.com'
11
+ s.files = `git ls-files`.split("\n")
12
+ s.require_paths = %w(lib)
13
+ s.homepage =
14
+ 'https://rubygems.org/gems/blurhash_ruby'
15
+ s.license = 'MIT'
16
+ s.extensions = %w[ext/blurhash_decoder/extconf.rb ext/blurhash_encoder/extconf.rb]
17
+ end
@@ -0,0 +1,39 @@
1
+ #include "decode.h"
2
+
3
+ #define STB_IMAGE_WRITE_IMPLEMENTATION
4
+ #include "stb_writer.h"
5
+ #include <ruby.h>
6
+
7
+ VALUE DECODER = Qnil; /* Ruby Module */
8
+
9
+ VALUE method_decode(VALUE self, VALUE blurhash, VALUE heigh, VALUE widt, VALUE punc) {
10
+ const char * hash = StringValuePtr(blurhash);
11
+ int height = NUM2INT(heigh);
12
+ int width = NUM2INT(widt);
13
+ int punch = NUM2INT(punc);
14
+
15
+ const char * output_file = "tmp/out.png";
16
+
17
+ const int nChannels = 4;
18
+
19
+ uint8_t * bytes = decode(hash, width, height, punch, nChannels);
20
+ if (!bytes) {
21
+ fprintf(stderr, "%s is not a valid blurhash, decoding failed.\n", hash);
22
+ return 1;
23
+ }
24
+
25
+ if (stbi_write_png(output_file, width, height, nChannels, bytes, nChannels * width) == 0) {
26
+ fprintf(stderr, "Failed to write PNG file %s\n", output_file);
27
+ return 1;
28
+ }
29
+ freePixelArray(bytes);
30
+ fprintf(stdout, "Decoded blurhash successfully, wrote PNG file %s\n", output_file);
31
+ return 0;
32
+ }
33
+
34
+ void
35
+ Init_blurhash_decoder(void) {
36
+ DECODER = rb_define_module("DECODER");
37
+ rb_define_method(DECODER, "decode", method_decode, 4);
38
+ }
39
+
@@ -0,0 +1,148 @@
1
+ #include "decode.h"
2
+ #include "../common.h"
3
+
4
+ static char chars[83] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~";
5
+
6
+ static inline uint8_t clampToUByte(int * src) {
7
+ if( *src >= 0 && *src <= 255 )
8
+ return *src;
9
+ return (*src < 0) ? 0 : 255;
10
+ }
11
+
12
+ static inline uint8_t * createByteArray(int size) {
13
+ return (uint8_t *)malloc(size * sizeof(uint8_t));
14
+ }
15
+
16
+ int decodeToInt(const char * string, int start, int end) {
17
+ int value = 0, iter1 = 0, iter2 = 0;
18
+ for( iter1 = start; iter1 < end; iter1 ++) {
19
+ int index = -1;
20
+ for(iter2 = 0; iter2 < 83; iter2 ++) {
21
+ if (chars[iter2] == string[iter1]) {
22
+ index = iter2;
23
+ break;
24
+ }
25
+ }
26
+ if (index == -1) return -1;
27
+ value = value * 83 + index;
28
+ }
29
+ return value;
30
+ }
31
+
32
+ bool isValidBlurhash(const char * blurhash) {
33
+
34
+ const int hashLength = strlen(blurhash);
35
+
36
+ if ( !blurhash || strlen(blurhash) < 6) return false;
37
+
38
+ int sizeFlag = decodeToInt(blurhash, 0, 1); //Get size from first character
39
+ int numY = (int)floorf(sizeFlag / 9) + 1;
40
+ int numX = (sizeFlag % 9) + 1;
41
+
42
+ if (hashLength != 4 + 2 * numX * numY) return false;
43
+ return true;
44
+ }
45
+
46
+ void decodeDC(int value, float * r, float * g, float * b) {
47
+ *r = sRGBToLinear(value >> 16); // R-component
48
+ *g = sRGBToLinear((value >> 8) & 255); // G-Component
49
+ *b = sRGBToLinear(value & 255); // B-Component
50
+ }
51
+
52
+ void decodeAC(int value, float maximumValue, float * r, float * g, float * b) {
53
+ int quantR = (int)floorf(value / (19 * 19));
54
+ int quantG = (int)floorf(value / 19) % 19;
55
+ int quantB = (int)value % 19;
56
+
57
+ *r = signPow(((float)quantR - 9) / 9, 2.0) * maximumValue;
58
+ *g = signPow(((float)quantG - 9) / 9, 2.0) * maximumValue;
59
+ *b = signPow(((float)quantB - 9) / 9, 2.0) * maximumValue;
60
+ }
61
+
62
+ int decodeToArray(const char * blurhash, int width, int height, int punch, int nChannels, uint8_t * pixelArray) {
63
+ if (! isValidBlurhash(blurhash)) return -1;
64
+ if (punch < 1) punch = 1;
65
+
66
+ int sizeFlag = decodeToInt(blurhash, 0, 1);
67
+ int numY = (int)floorf(sizeFlag / 9) + 1;
68
+ int numX = (sizeFlag % 9) + 1;
69
+ int iter = 0;
70
+
71
+ float r = 0, g = 0, b = 0;
72
+ int quantizedMaxValue = decodeToInt(blurhash, 1, 2);
73
+ if (quantizedMaxValue == -1) return -1;
74
+
75
+ float maxValue = ((float)(quantizedMaxValue + 1)) / 166;
76
+
77
+ int colors_size = numX * numY;
78
+ float colors[colors_size][3];
79
+
80
+ for(iter = 0; iter < colors_size; iter ++) {
81
+ if (iter == 0) {
82
+ int value = decodeToInt(blurhash, 2, 6);
83
+ if (value == -1) return -1;
84
+ decodeDC(value, &r, &g, &b);
85
+ colors[iter][0] = r;
86
+ colors[iter][1] = g;
87
+ colors[iter][2] = b;
88
+
89
+ } else {
90
+ int value = decodeToInt(blurhash, 4 + iter * 2, 6 + iter * 2);
91
+ if (value == -1) return -1;
92
+ decodeAC(value, maxValue * punch, &r, &g, &b);
93
+ colors[iter][0] = r;
94
+ colors[iter][1] = g;
95
+ colors[iter][2] = b;
96
+ }
97
+ }
98
+
99
+ int bytesPerRow = width * nChannels;
100
+ int x = 0, y = 0, i = 0, j = 0;
101
+ int intR = 0, intG = 0, intB = 0;
102
+
103
+ for(y = 0; y < height; y ++) {
104
+ for(x = 0; x < width; x ++) {
105
+
106
+ float r = 0, g = 0, b = 0;
107
+
108
+ for(j = 0; j < numY; j ++) {
109
+ for(i = 0; i < numX; i ++) {
110
+ float basics = cos((M_PI * x * i) / width) * cos((M_PI * y * j) / height);
111
+ int idx = i + j * numX;
112
+ r += colors[idx][0] * basics;
113
+ g += colors[idx][1] * basics;
114
+ b += colors[idx][2] * basics;
115
+ }
116
+ }
117
+
118
+ intR = linearTosRGB(r);
119
+ intG = linearTosRGB(g);
120
+ intB = linearTosRGB(b);
121
+
122
+ pixelArray[nChannels * x + 0 + y * bytesPerRow] = clampToUByte(&intR);
123
+ pixelArray[nChannels * x + 1 + y * bytesPerRow] = clampToUByte(&intG);
124
+ pixelArray[nChannels * x + 2 + y * bytesPerRow] = clampToUByte(&intB);
125
+
126
+ if (nChannels == 4)
127
+ pixelArray[nChannels * x + 3 + y * bytesPerRow] = 255; // If nChannels=4, treat each pixel as RGBA instead of RGB
128
+
129
+ }
130
+ }
131
+
132
+ return 0;
133
+ }
134
+
135
+ uint8_t * decode(const char * blurhash, int width, int height, int punch, int nChannels) {
136
+ int bytesPerRow = width * nChannels;
137
+ uint8_t * pixelArray = createByteArray(bytesPerRow * height);
138
+
139
+ if (decodeToArray(blurhash, width, height, punch, nChannels, pixelArray) == -1)
140
+ return NULL;
141
+ return pixelArray;
142
+ }
143
+
144
+ void freePixelArray(uint8_t * pixelArray) {
145
+ if (pixelArray) {
146
+ free(pixelArray);
147
+ }
148
+ }
@@ -0,0 +1,54 @@
1
+ #ifndef __BLURHASH_DECODE_H__
2
+
3
+ #define __BLURHASH_DECODE_H
4
+
5
+ #include <math.h>
6
+ #include <stdbool.h>
7
+ #include <string.h>
8
+ #include <stdlib.h>
9
+ #include <stdint.h>
10
+
11
+ /*
12
+ decode : Returns the pixel array of the result image given the blurhash string,
13
+ Parameters :
14
+ blurhash : A string representing the blurhash to be decoded.
15
+ width : Width of the resulting image
16
+ height : Height of the resulting image
17
+ punch : The factor to improve the contrast, default = 1
18
+ nChannels : Number of channels in the resulting image array, 3 = RGB, 4 = RGBA
19
+ Returns : A pointer to memory region where pixels are stored in (H, W, C) format
20
+ */
21
+ uint8_t * decode(const char * blurhash, int width, int height, int punch, int nChannels);
22
+
23
+ /*
24
+ decodeToArray : Decodes the blurhash and copies the pixels to pixelArray,
25
+ This method is suggested if you use an external memory allocator for pixelArray.
26
+ pixelArray should be of size : width * height * nChannels
27
+ Parameters :
28
+ blurhash : A string representing the blurhash to be decoded.
29
+ width : Width of the resulting image
30
+ height : Height of the resulting image
31
+ punch : The factor to improve the contrast, default = 1
32
+ nChannels : Number of channels in the resulting image array, 3 = RGB, 4 = RGBA
33
+ pixelArray : Pointer to memory region where pixels needs to be copied.
34
+ Returns : int, -1 if error 0 if successful
35
+ */
36
+ int decodeToArray(const char * blurhash, int width, int height, int punch, int nChannels, uint8_t * pixelArray);
37
+
38
+ /*
39
+ isValidBlurhash : Checks if the Blurhash is valid or not.
40
+ Parameters :
41
+ blurhash : A string representing the blurhash
42
+ Returns : bool (true if it is a valid blurhash, else false)
43
+ */
44
+ bool isValidBlurhash(const char * blurhash);
45
+
46
+ /*
47
+ freePixelArray : Frees the pixel array
48
+ Parameters :
49
+ pixelArray : Pixel array pointer which will be freed.
50
+ Returns : void (None)
51
+ */
52
+ void freePixelArray(uint8_t * pixelArray);
53
+
54
+ #endif
@@ -0,0 +1,6 @@
1
+ require "mkmf"
2
+
3
+ abort "missing malloc()" unless have_func "malloc"
4
+ abort "missing free()" unless have_func "free"
5
+
6
+ create_makefile("blurhash_decoder/blurhash_decoder")