blurhash_decoder 0.0.7 → 0.0.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b413ba2921f9347cc8f62b3b74c19bc4baa87d486b001178e0b19e423d303411
4
- data.tar.gz: 7ca2a4c9f3e3208f9692aa4817ca5c79bad71429ace8ba787e86dd3a58ebb98a
3
+ metadata.gz: b0221d3511057d149926cc067e2a8e2eb51ff0c724476666e618df955160626e
4
+ data.tar.gz: a271106fec9b1e3872b0ab1a8ec7753e8b4e68a055887ba0dee57e9bd3964d1e
5
5
  SHA512:
6
- metadata.gz: 8db69d6d4b520e2820501f8e59824ebd75663a99c2dc628730caaf3c6d93e21a908ee95e66826d04223d19485ef9948647b23d98d82fb8e27d2d7e7b300f041f
7
- data.tar.gz: 367d99df65cac8c57f88a126e15f5f62902e1091d500ac2f4a519763fae54e02181764585db62223c30014aa398fe4cc39c5c6a8968c8aa20043a220999a02a9
6
+ metadata.gz: dbbb92c47bcb19a4445e58c1a22ec038642fce18d01209a9b528b70707c42905385164aaf48b9b0b9f2165f7d7a1118ccef7533b2e58e56e37ca862fba8d98a2
7
+ data.tar.gz: 125ef0207f696e1bf40055e8ffdbd14419b47ce83e0e7efb9bc7dfb79dbe55b685efa04c4d894a55d17a4cd00c010b7e437b2187167a4d6234df454c4c58ea12
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ tmp
2
+ lib/stuart_geo/*.bundle
3
+ lib/stuart_geo/*.so
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/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'
5
+ end
6
+
7
+ Rake::ExtensionTask.new "blurhash_encoder" do |ext|
8
+ ext.lib_dir = 'lib/blurhash_encoder'
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_decoder'
6
+ s.version = '0.0.11'
7
+ s.summary = "A blurhash decoder gem!"
8
+ s.description = "A simple blurhash decoder gem using c."
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_decoder'
15
+ s.license = 'MIT'
16
+ s.extensions = %w[ext/blurhash_decoder/extconf.rb ext/blurhash_encoder/extconf.rb]
17
+ end
@@ -0,0 +1,205 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+ #include<math.h>
4
+ #include <stdbool.h>
5
+
6
+ #define STB_IMAGE_WRITE_IMPLEMENTATION
7
+ #include "stb_writer.h"
8
+
9
+ #define M_PI 3.14159265358979323846
10
+
11
+ VALUE DECODER = Qnil; /* Ruby Module */
12
+ static char chars[83] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~";
13
+
14
+ static inline int linearTosRGB(float value) {
15
+ float v = fmaxf(0, fminf(1, value));
16
+ if(v <= 0.0031308) return v * 12.92 * 255 + 0.5;
17
+ else return (1.055 * powf(v, 1 / 2.4) - 0.055) * 255 + 0.5;
18
+ }
19
+
20
+ static inline float sRGBToLinear(int value) {
21
+ float v = (float)value / 255;
22
+ if(v <= 0.04045) return v / 12.92;
23
+ else return powf((v + 0.055) / 1.055, 2.4);
24
+ }
25
+
26
+ static inline float signPow(float value, float exp) {
27
+ return copysignf(powf(fabsf(value), exp), value);
28
+ }
29
+
30
+ static inline uint8_t clampToUByte(int * src) {
31
+ if( *src >= 0 && *src <= 255 )
32
+ return *src;
33
+ return (*src < 0) ? 0 : 255;
34
+ }
35
+
36
+ static inline uint8_t * createByteArray(int size) {
37
+ return (uint8_t *)malloc(size * sizeof(uint8_t));
38
+ }
39
+
40
+ int decodeToInt(const char * string, int start, int end) {
41
+ int value = 0, iter1 = 0, iter2 = 0;
42
+ for( iter1 = start; iter1 < end; iter1 ++) {
43
+ int index = -1;
44
+ for(iter2 = 0; iter2 < 83; iter2 ++) {
45
+ if (chars[iter2] == string[iter1]) {
46
+ index = iter2;
47
+ break;
48
+ }
49
+ }
50
+ if (index == -1) return -1;
51
+ value = value * 83 + index;
52
+ }
53
+ return value;
54
+ }
55
+
56
+ bool isValidBlurhash(const char * blurhash) {
57
+
58
+ const int hashLength = strlen(blurhash);
59
+
60
+ if ( !blurhash || strlen(blurhash) < 6) return false;
61
+
62
+ int sizeFlag = decodeToInt(blurhash, 0, 1); //Get size from first character
63
+ int numY = (int)floorf(sizeFlag / 9) + 1;
64
+ int numX = (sizeFlag % 9) + 1;
65
+
66
+ if (hashLength != 4 + 2 * numX * numY) return false;
67
+ return true;
68
+ }
69
+
70
+ void decodeDC(int value, float * r, float * g, float * b) {
71
+ *r = sRGBToLinear(value >> 16); // R-component
72
+ *g = sRGBToLinear((value >> 8) & 255); // G-Component
73
+ *b = sRGBToLinear(value & 255); // B-Component
74
+ }
75
+
76
+ void decodeAC(int value, float maximumValue, float * r, float * g, float * b) {
77
+ int quantR = (int)floorf(value / (19 * 19));
78
+ int quantG = (int)floorf(value / 19) % 19;
79
+ int quantB = (int)value % 19;
80
+
81
+ *r = signPow(((float)quantR - 9) / 9, 2.0) * maximumValue;
82
+ *g = signPow(((float)quantG - 9) / 9, 2.0) * maximumValue;
83
+ *b = signPow(((float)quantB - 9) / 9, 2.0) * maximumValue;
84
+ }
85
+
86
+ int decodeToArray(const char * blurhash, int width, int height, int punch, int nChannels, uint8_t * pixelArray) {
87
+ if (! isValidBlurhash(blurhash)) return -1;
88
+ if (punch < 1) punch = 1;
89
+
90
+ int sizeFlag = decodeToInt(blurhash, 0, 1);
91
+ int numY = (int)floorf(sizeFlag / 9) + 1;
92
+ int numX = (sizeFlag % 9) + 1;
93
+ int iter = 0;
94
+
95
+ float r = 0, g = 0, b = 0;
96
+ int quantizedMaxValue = decodeToInt(blurhash, 1, 2);
97
+ if (quantizedMaxValue == -1) return -1;
98
+
99
+ float maxValue = ((float)(quantizedMaxValue + 1)) / 166;
100
+
101
+ int colors_size = numX * numY;
102
+ float colors[colors_size][3];
103
+
104
+ for(iter = 0; iter < colors_size; iter ++) {
105
+ if (iter == 0) {
106
+ int value = decodeToInt(blurhash, 2, 6);
107
+ if (value == -1) return -1;
108
+ decodeDC(value, &r, &g, &b);
109
+ colors[iter][0] = r;
110
+ colors[iter][1] = g;
111
+ colors[iter][2] = b;
112
+
113
+ } else {
114
+ int value = decodeToInt(blurhash, 4 + iter * 2, 6 + iter * 2);
115
+ if (value == -1) return -1;
116
+ decodeAC(value, maxValue * punch, &r, &g, &b);
117
+ colors[iter][0] = r;
118
+ colors[iter][1] = g;
119
+ colors[iter][2] = b;
120
+ }
121
+ }
122
+
123
+ int bytesPerRow = width * nChannels;
124
+ int x = 0, y = 0, i = 0, j = 0;
125
+ int intR = 0, intG = 0, intB = 0;
126
+
127
+ for(y = 0; y < height; y ++) {
128
+ for(x = 0; x < width; x ++) {
129
+
130
+ float r = 0, g = 0, b = 0;
131
+
132
+ for(j = 0; j < numY; j ++) {
133
+ for(i = 0; i < numX; i ++) {
134
+ float basics = cos((M_PI * x * i) / width) * cos((M_PI * y * j) / height);
135
+ int idx = i + j * numX;
136
+ r += colors[idx][0] * basics;
137
+ g += colors[idx][1] * basics;
138
+ b += colors[idx][2] * basics;
139
+ }
140
+ }
141
+
142
+ intR = linearTosRGB(r);
143
+ intG = linearTosRGB(g);
144
+ intB = linearTosRGB(b);
145
+
146
+ pixelArray[nChannels * x + 0 + y * bytesPerRow] = clampToUByte(&intR);
147
+ pixelArray[nChannels * x + 1 + y * bytesPerRow] = clampToUByte(&intG);
148
+ pixelArray[nChannels * x + 2 + y * bytesPerRow] = clampToUByte(&intB);
149
+
150
+ if (nChannels == 4)
151
+ pixelArray[nChannels * x + 3 + y * bytesPerRow] = 255; // If nChannels=4, treat each pixel as RGBA instead of RGB
152
+
153
+ }
154
+ }
155
+
156
+ return 0;
157
+ }
158
+
159
+ uint8_t * decode(const char * blurhash, int width, int height, int punch, int nChannels) {
160
+ int bytesPerRow = width * nChannels;
161
+ uint8_t * pixelArray = createByteArray(bytesPerRow * height);
162
+
163
+ if (decodeToArray(blurhash, width, height, punch, nChannels, pixelArray) == -1)
164
+ return NULL;
165
+ return pixelArray;
166
+ }
167
+
168
+ void freePixelArray(uint8_t * pixelArray) {
169
+ if (pixelArray) {
170
+ free(pixelArray);
171
+ }
172
+ }
173
+
174
+ VALUE method_decode(VALUE self, VALUE blurhash, VALUE heigh, VALUE widt, VALUE punc) {
175
+ const char * hash = StringValuePtr(blurhash);
176
+ int height = NUM2INT(heigh);
177
+ int width = NUM2INT(widt);
178
+ int punch = NUM2INT(punc);
179
+
180
+ const char * output_file = "tmp/out.png";
181
+
182
+ const int nChannels = 4;
183
+
184
+ uint8_t * bytes = decode(hash, width, height, punch, nChannels);
185
+ if (!bytes) {
186
+ // fprintf(stderr, "%s is not a valid blurhash, decoding failed.\n", hash);
187
+ return 1;
188
+ }
189
+
190
+ if (stbi_write_png(output_file, width, height, nChannels, bytes, nChannels * width) == 0) {
191
+ // fprintf(stderr, "Failed to write PNG file %s\n", output_file);
192
+ return 1;
193
+ }
194
+ freePixelArray(bytes);
195
+ // fprintf(stdout, "Decoded blurhash successfully, wrote PNG file %s\n", output_file);
196
+ return 0;
197
+ // return rb_float_new(5); /* Convert C double to Ruby float */
198
+ }
199
+
200
+ void
201
+ Init_blurhash_decoder(void) {
202
+ DECODER = rb_define_module("DECODER");
203
+ rb_define_method(DECODER, "decode", method_decode, 4);
204
+ }
205
+