Skip to content

Instantly share code, notes, and snippets.

@anael-seghezzi
Created February 8, 2022 13:38
Show Gist options
  • Save anael-seghezzi/aadc0a624f7697d4f20de7b7d8372e34 to your computer and use it in GitHub Desktop.
Save anael-seghezzi/aadc0a624f7697d4f20de7b7d8372e34 to your computer and use it in GitHub Desktop.
simple lossy procedure preceding lz4 compression
// simple lossy procedure preceding lz4 compression
// default: win_size = 64, max_loss = 2
// tested with lz4hc - LZ4HC_CLEVEL_DEFAULT
void lossy_lz4_rgb(uint8_t *data, int w, int h, int win_size, float max_loss)
{
float max_loss2 = max_loss*max_loss;
int y, x;
for (y = 0; y < h; y++)
for (x = 0; x < w; x++) {
uint8_t *pixel;
float r, g, b;
int yy, xx, my, mx;
// R2 sequence
float r2 = 0.754877645 * x + 0.569840259 * y;
float r2i = r2 - (int)r2;
// triangulate and remap to max_loss
float dither = r2i < 0.5 ? r2i = r2i * 2.0 : 2.0 - r2i * 2.0;
dither = (dither * 2.0 - 1.0) * max_loss;
// add dither (hurt compression but remove banding)
pixel = data + (y * w + x) * 3;
r = pixel[0] + dither;
g = pixel[1] + dither;
b = pixel[2] + dither;
// window search starting from current pixel
// lz4 max offset is 65535 bytes so it might not hold for large images
my = M_MAX(0, y - win_size);
mx = M_MAX(0, x - win_size);
for (yy = y; yy >= my; yy--)
for (xx = x; xx >= mx; xx--) {
if (!(xx == x && yy == y)) {
uint8_t *win_pixel = data + (yy * w + xx) * 3;
float dr = win_pixel[0] - r;
float dg = win_pixel[1] - g;
float db = win_pixel[2] - b;
float d = dr*dr*0.3 + dg*dg*0.5 + db*db*0.2;
if (d < max_loss2) {
pixel[0] = win_pixel[0];
pixel[1] = win_pixel[1];
pixel[2] = win_pixel[2];
goto next_pixel;
}
}
}
next_pixel:;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment