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.
@@ -0,0 +1,52 @@
1
+ #include "encode.h"
2
+
3
+ #define STB_IMAGE_IMPLEMENTATION
4
+ #include "stb_image.h"
5
+
6
+ #include <ruby.h>
7
+ #include <stdio.h>
8
+ #include <string.h>
9
+
10
+
11
+ VALUE ENCODER = Qnil; /* Ruby Module */
12
+
13
+ const char *blurHashForFile(int xComponents, int yComponents,const char *filename);
14
+
15
+ VALUE method_encode(VALUE self, VALUE x, VALUE y) {
16
+ int xComponents = NUM2INT(x);
17
+ int yComponents = NUM2INT(y);
18
+
19
+ const char * input_file = "tmp/in.png";
20
+
21
+ if(xComponents < 1 || xComponents > 8 || yComponents < 1 || yComponents > 8) {
22
+ fprintf(stderr, "Component counts must be between 1 and 8.\n");
23
+ return 1;
24
+ }
25
+
26
+ const char *hash = blurHashForFile(xComponents, yComponents, input_file);
27
+ if(!hash) {
28
+ fprintf(stderr, "Failed to load image file \"%s\".\n", input_file);
29
+ return 1;
30
+ }
31
+
32
+ return rb_str_new(hash, strlen(hash));
33
+ }
34
+
35
+ const char *blurHashForFile(int xComponents, int yComponents,const char *filename) {
36
+ int width, height, channels;
37
+ unsigned char *data = stbi_load(filename, &width, &height, &channels, 3);
38
+ if(!data) return NULL;
39
+
40
+ const char *hash = blurHashForPixels(xComponents, yComponents, width, height, data, width * 3);
41
+
42
+ stbi_image_free(data);
43
+
44
+ return hash;
45
+ }
46
+
47
+ void
48
+ Init_blurhash_encoder(void) {
49
+ ENCODER = rb_define_module("ENCODER");
50
+ rb_define_method(ENCODER, "encode", method_encode, 2);
51
+ }
52
+
@@ -0,0 +1,116 @@
1
+ #include "encode.h"
2
+ #include "../common.h"
3
+
4
+ #include <string.h>
5
+
6
+ static float *multiplyBasisFunction(int xComponent, int yComponent, int width, int height, uint8_t *rgb, size_t bytesPerRow);
7
+ static char *encode_int(int value, int length, char *destination);
8
+
9
+ static int encodeDC(float r, float g, float b);
10
+ static int encodeAC(float r, float g, float b, float maximumValue);
11
+
12
+ const char *blurHashForPixels(int xComponents, int yComponents, int width, int height, uint8_t *rgb, size_t bytesPerRow) {
13
+ static char buffer[2 + 4 + (9 * 9 - 1) * 2 + 1];
14
+
15
+ if(xComponents < 1 || xComponents > 9) return NULL;
16
+ if(yComponents < 1 || yComponents > 9) return NULL;
17
+
18
+ float factors[yComponents][xComponents][3];
19
+ memset(factors, 0, sizeof(factors));
20
+
21
+ for(int y = 0; y < yComponents; y++) {
22
+ for(int x = 0; x < xComponents; x++) {
23
+ float *factor = multiplyBasisFunction(x, y, width, height, rgb, bytesPerRow);
24
+ factors[y][x][0] = factor[0];
25
+ factors[y][x][1] = factor[1];
26
+ factors[y][x][2] = factor[2];
27
+ }
28
+ }
29
+
30
+ float *dc = factors[0][0];
31
+ float *ac = dc + 3;
32
+ int acCount = xComponents * yComponents - 1;
33
+ char *ptr = buffer;
34
+
35
+ int sizeFlag = (xComponents - 1) + (yComponents - 1) * 9;
36
+ ptr = encode_int(sizeFlag, 1, ptr);
37
+
38
+ float maximumValue;
39
+ if(acCount > 0) {
40
+ float actualMaximumValue = 0;
41
+ for(int i = 0; i < acCount * 3; i++) {
42
+ actualMaximumValue = fmaxf(fabsf(ac[i]), actualMaximumValue);
43
+ }
44
+
45
+ int quantisedMaximumValue = fmaxf(0, fminf(82, floorf(actualMaximumValue * 166 - 0.5)));
46
+ maximumValue = ((float)quantisedMaximumValue + 1) / 166;
47
+ ptr = encode_int(quantisedMaximumValue, 1, ptr);
48
+ } else {
49
+ maximumValue = 1;
50
+ ptr = encode_int(0, 1, ptr);
51
+ }
52
+
53
+ ptr = encode_int(encodeDC(dc[0], dc[1], dc[2]), 4, ptr);
54
+
55
+ for(int i = 0; i < acCount; i++) {
56
+ ptr = encode_int(encodeAC(ac[i * 3 + 0], ac[i * 3 + 1], ac[i * 3 + 2], maximumValue), 2, ptr);
57
+ }
58
+
59
+ *ptr = 0;
60
+
61
+ return buffer;
62
+ }
63
+
64
+ static float *multiplyBasisFunction(int xComponent, int yComponent, int width, int height, uint8_t *rgb, size_t bytesPerRow) {
65
+ float r = 0, g = 0, b = 0;
66
+ float normalisation = (xComponent == 0 && yComponent == 0) ? 1 : 2;
67
+
68
+ for(int y = 0; y < height; y++) {
69
+ for(int x = 0; x < width; x++) {
70
+ float basis = cosf(M_PI * xComponent * x / width) * cosf(M_PI * yComponent * y / height);
71
+ r += basis * sRGBToLinear(rgb[3 * x + 0 + y * bytesPerRow]);
72
+ g += basis * sRGBToLinear(rgb[3 * x + 1 + y * bytesPerRow]);
73
+ b += basis * sRGBToLinear(rgb[3 * x + 2 + y * bytesPerRow]);
74
+ }
75
+ }
76
+
77
+ float scale = normalisation / (width * height);
78
+
79
+ static float result[3];
80
+ result[0] = r * scale;
81
+ result[1] = g * scale;
82
+ result[2] = b * scale;
83
+
84
+ return result;
85
+ }
86
+
87
+
88
+
89
+ static int encodeDC(float r, float g, float b) {
90
+ int roundedR = linearTosRGB(r);
91
+ int roundedG = linearTosRGB(g);
92
+ int roundedB = linearTosRGB(b);
93
+ return (roundedR << 16) + (roundedG << 8) + roundedB;
94
+ }
95
+
96
+ static int encodeAC(float r, float g, float b, float maximumValue) {
97
+ int quantR = fmaxf(0, fminf(18, floorf(signPow(r / maximumValue, 0.5) * 9 + 9.5)));
98
+ int quantG = fmaxf(0, fminf(18, floorf(signPow(g / maximumValue, 0.5) * 9 + 9.5)));
99
+ int quantB = fmaxf(0, fminf(18, floorf(signPow(b / maximumValue, 0.5) * 9 + 9.5)));
100
+
101
+ return quantR * 19 * 19 + quantG * 19 + quantB;
102
+ }
103
+
104
+ static char characters[83]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~";
105
+
106
+ static char *encode_int(int value, int length, char *destination) {
107
+ int divisor = 1;
108
+ for(int i = 0; i < length - 1; i++) divisor *= 83;
109
+
110
+ for(int i = 0; i < length; i++) {
111
+ int digit = (value / divisor) % 83;
112
+ divisor /= 83;
113
+ *destination++ = characters[digit];
114
+ }
115
+ return destination;
116
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef __BLURHASH_ENCODE_H__
2
+ #define __BLURHASH_ENCODE_H__
3
+
4
+ #include <stdint.h>
5
+ #include <stdlib.h>
6
+
7
+ const char *blurHashForPixels(int xComponents, int yComponents, int width, int height, uint8_t *rgb, size_t bytesPerRow);
8
+
9
+ #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_encoder/blurhash_encoder")