diff --git a/C/encode.c b/C/encode.c index b744851b..501cbf54 100644 --- a/C/encode.c +++ b/C/encode.c @@ -7,7 +7,7 @@ #define M_PI 3.14159265358979323846 #endif -static float *multiplyBasisFunction(int xComponent, int yComponent, int width, int height, uint8_t *rgb, size_t bytesPerRow); +static void multiplyBasisFunction(float *result, 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); @@ -16,25 +16,23 @@ 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]; - +const char *blurHashForPixels_r(char *buffer, int size, int xComponents, int yComponents, int width, int height, uint8_t *rgb, size_t bytesPerRow) { if(xComponents < 1 || xComponents > 9) return NULL; if(yComponents < 1 || yComponents > 9) return NULL; - float factors[yComponents][xComponents][3]; - memset(factors, 0, sizeof(factors)); + if(size < 2 + 4 + (xComponents * yComponents - 1) * 2 + 1) return NULL; + + int count = (sizeof(float)) * yComponents * xComponents * 3; + float* factors = calloc(count, sizeof(float)); + if(!factors) return NULL; 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]; + multiplyBasisFunction(factors + (y * xComponents + x) * 3, x, y, width, height, rgb, bytesPerRow); } } - float *dc = factors[0][0]; + float *dc = factors; float *ac = dc + 3; int acCount = xComponents * yComponents - 1; char *ptr = buffer; @@ -49,7 +47,7 @@ const char *blurHashForPixels(int xComponents, int yComponents, int width, int h actualMaximumValue = fmaxf(fabsf(ac[i]), actualMaximumValue); } - int quantisedMaximumValue = fmaxf(0, fminf(82, floorf(actualMaximumValue * 166 - 0.5))); + int quantisedMaximumValue = (int)fmax(0, fmin(82, floor(actualMaximumValue * 166 - 0.5))); maximumValue = ((float)quantisedMaximumValue + 1) / 166; ptr = encode_int(quantisedMaximumValue, 1, ptr); } else { @@ -65,16 +63,22 @@ const char *blurHashForPixels(int xComponents, int yComponents, int width, int h *ptr = 0; + free(factors); return buffer; } -static float *multiplyBasisFunction(int xComponent, int yComponent, int width, int height, uint8_t *rgb, size_t bytesPerRow) { +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]; + return blurHashForPixels_r(buffer, sizeof(buffer), xComponents, yComponents, width, height, rgb, bytesPerRow); +} + +static void multiplyBasisFunction(float *result, 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; + float normalisation = (xComponent == 0 && yComponent == 0) ? 1.f : 2.f; 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); + float basis = cosf((float)M_PI * xComponent * x / width) * cosf((float)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]); @@ -83,24 +87,21 @@ static float *multiplyBasisFunction(int xComponent, int yComponent, int width, i 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; + if(v <= 0.0031308) return (int)(v * 12.92 * 255 + 0.5); + else return (int)((1.055 * powf(v, 1.f / 2.4f) - 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); + if(v <= 0.04045) return v / 12.92f; + else return powf((v + 0.055f) / 1.055f, 2.4f); } static int encodeDC(float r, float g, float b) { @@ -111,9 +112,9 @@ static int encodeDC(float r, float g, float b) { } 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))); + int quantR = (int)fmaxf(0.f, fminf(18.f, floorf(signPow(r / maximumValue, 0.5f) * 9 + 9.5f))); + int quantG = (int)fmaxf(0.f, fminf(18.f, floorf(signPow(g / maximumValue, 0.5f) * 9 + 9.5f))); + int quantB = (int)fmaxf(0.f, fminf(18.f, floorf(signPow(b / maximumValue, 0.5f) * 9 + 9.5f))); return quantR * 19 * 19 + quantG * 19 + quantB; } @@ -122,7 +123,7 @@ static float signPow(float value, float exp) { return copysignf(powf(fabsf(value), exp), value); } -static char characters[83]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~"; +static const char characters[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~"; static char *encode_int(int value, int length, char *destination) { int divisor = 1; diff --git a/C/encode.h b/C/encode.h index 10e3a0c1..05a5c6a0 100644 --- a/C/encode.h +++ b/C/encode.h @@ -5,5 +5,6 @@ #include const char *blurHashForPixels(int xComponents, int yComponents, int width, int height, uint8_t *rgb, size_t bytesPerRow); +const char *blurHashForPixels_r(char *out, int size, int xComponents, int yComponents, int width, int height, uint8_t *rgb, size_t bytesPerRow); #endif