forked from woltapp/blurhash
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathencode.c
More file actions
137 lines (107 loc) · 4.17 KB
/
Copy pathencode.c
File metadata and controls
137 lines (107 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "encode.h"
#include <string.h>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
static float *multiplyBasisFunction(int xComponent, int yComponent, int width, int height, uint8_t *rgb, size_t bytesPerRow);
static char *encode_int(int value, int length, char *destination);
static int linearTosRGB(float value);
static float sRGBToLinear(int value);
static int encodeDC(float r, float g, float b);
static int encodeAC(float r, float g, float b, float maximumValue);
static float signPow(float value, float exp);
const char *blurHashForPixels(int xComponents, int yComponents, int width, int height, uint8_t *rgb, size_t bytesPerRow) {
static char buffer[2 + 4 + (9 * 9 - 1) * 2 + 1];
if(xComponents < 1 || xComponents > 9) return NULL;
if(yComponents < 1 || yComponents > 9) return NULL;
float factors[yComponents][xComponents][3];
memset(factors, 0, sizeof(factors));
for(int y = 0; y < yComponents; y++) {
for(int x = 0; x < xComponents; x++) {
float *factor = multiplyBasisFunction(x, y, width, height, rgb, bytesPerRow);
factors[y][x][0] = factor[0];
factors[y][x][1] = factor[1];
factors[y][x][2] = factor[2];
}
}
float *dc = factors[0][0];
float *ac = dc + 3;
int acCount = xComponents * yComponents - 1;
char *ptr = buffer;
int sizeFlag = (xComponents - 1) + (yComponents - 1) * 9;
ptr = encode_int(sizeFlag, 1, ptr);
float maximumValue;
if(acCount > 0) {
float actualMaximumValue = 0;
for(int i = 0; i < acCount * 3; i++) {
actualMaximumValue = fmaxf(fabsf(ac[i]), actualMaximumValue);
}
int quantisedMaximumValue = fmaxf(0, fminf(82, floorf(actualMaximumValue * 166 - 0.5)));
maximumValue = ((float)quantisedMaximumValue + 1) / 166;
ptr = encode_int(quantisedMaximumValue, 1, ptr);
} else {
maximumValue = 1;
ptr = encode_int(0, 1, ptr);
}
ptr = encode_int(encodeDC(dc[0], dc[1], dc[2]), 4, ptr);
for(int i = 0; i < acCount; i++) {
ptr = encode_int(encodeAC(ac[i * 3 + 0], ac[i * 3 + 1], ac[i * 3 + 2], maximumValue), 2, ptr);
}
*ptr = 0;
return buffer;
}
static float *multiplyBasisFunction(int xComponent, int yComponent, int width, int height, uint8_t *rgb, size_t bytesPerRow) {
float r = 0, g = 0, b = 0;
float normalisation = (xComponent == 0 && yComponent == 0) ? 1 : 2;
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
float basis = cosf(M_PI * xComponent * x / width) * cosf(M_PI * yComponent * y / height);
r += basis * sRGBToLinear(rgb[3 * x + 0 + y * bytesPerRow]);
g += basis * sRGBToLinear(rgb[3 * x + 1 + y * bytesPerRow]);
b += basis * sRGBToLinear(rgb[3 * x + 2 + y * bytesPerRow]);
}
}
float scale = normalisation / (width * height);
static float result[3];
result[0] = r * scale;
result[1] = g * scale;
result[2] = b * scale;
return result;
}
static int linearTosRGB(float value) {
float v = fmaxf(0, fminf(1, value));
if(v <= 0.0031308) return v * 12.92 * 255 + 0.5;
else return (1.055 * powf(v, 1 / 2.4) - 0.055) * 255 + 0.5;
}
static float sRGBToLinear(int value) {
float v = (float)value / 255;
if(v <= 0.04045) return v / 12.92;
else return powf((v + 0.055) / 1.055, 2.4);
}
static int encodeDC(float r, float g, float b) {
int roundedR = linearTosRGB(r);
int roundedG = linearTosRGB(g);
int roundedB = linearTosRGB(b);
return (roundedR << 16) + (roundedG << 8) + roundedB;
}
static int encodeAC(float r, float g, float b, float maximumValue) {
int quantR = fmaxf(0, fminf(18, floorf(signPow(r / maximumValue, 0.5) * 9 + 9.5)));
int quantG = fmaxf(0, fminf(18, floorf(signPow(g / maximumValue, 0.5) * 9 + 9.5)));
int quantB = fmaxf(0, fminf(18, floorf(signPow(b / maximumValue, 0.5) * 9 + 9.5)));
return quantR * 19 * 19 + quantG * 19 + quantB;
}
static float signPow(float value, float exp) {
return copysignf(powf(fabsf(value), exp), value);
}
static char characters[83]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~";
static char *encode_int(int value, int length, char *destination) {
int divisor = 1;
for(int i = 0; i < length - 1; i++) divisor *= 83;
for(int i = 0; i < length; i++) {
int digit = (value / divisor) % 83;
divisor /= 83;
*destination++ = characters[digit];
}
return destination;
}