-
Notifications
You must be signed in to change notification settings - Fork 362
/
encode.c
116 lines (88 loc) · 3.56 KB
/
encode.c
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
#include "encode.h"
#include "common.h"
#include <string.h>
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 encodeDC(float r, float g, float b);
static int encodeAC(float r, float g, float b, float maximumValue);
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 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 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;
}