diff options
author | Daniel Eklöf <daniel@ekloef.se> | 2024-04-18 15:58:56 +0200 |
---|---|---|
committer | Daniel Eklöf <daniel@ekloef.se> | 2024-04-18 15:58:56 +0200 |
commit | 76e8e219743ff75288a30c93c301c17ba3f18c46 (patch) | |
tree | 1e877f031d0bb9499ed6ccb35ec031070242d657 /png.c | |
parent | d3c647694ac30fc8df6fb58dd1c2968f88ce1a4f (diff) | |
download | wbg-76e8e219743ff75288a30c93c301c17ba3f18c46.tar.gz |
png: do alpha pre-multiplication manually
Something's up with libpng's alpha-mode... it's required to get proper
alpha (transparency) on some images, but at the same time, that breaks
other images (they are rendered way too dark).
Doing the pre-multiplication manually seems to handle all images
correctly.
Diffstat (limited to 'png.c')
-rw-r--r-- | png.c | 30 |
1 files changed, 27 insertions, 3 deletions
@@ -68,12 +68,10 @@ png_load(FILE *fp, const char *path) png_set_strip_16(png_ptr); /* "pack" 16-bit colors to 8-bit */ png_set_bgr(png_ptr); - /* pixman expects pre-multiplied alpha */ - //png_set_alpha_mode(png_ptr, PNG_ALPHA_PREMULTIPLIED, 2.2); - /* Tell libpng to expand to RGB(A) when necessary, and tell pixman * whether we have alpha or not */ pixman_format_code_t format; + switch (color_type) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_GRAY_ALPHA: @@ -125,6 +123,32 @@ png_load(FILE *fp, const char *path) png_read_image(png_ptr, row_pointers); + /* pixman expects pre-multiplied alpha */ + if (format == PIXMAN_x8r8g8b8) { + for (int i = 0; i < height; i++) { + uint32_t *p = (uint32_t *)row_pointers[i]; + for (int j = 0; j < width; j++, p++) { + uint8_t a = (*p >> 24) & 0xff; + uint8_t r = (*p >> 16) & 0xff; + uint8_t g = (*p >> 8) & 0xff; + uint8_t b = (*p >> 0) & 0xff; + + if (a == 0xff) + continue; + + if (a == 0) { + r = g = b = 0; + } else { + r = r * a / 0xff; + g = g * a / 0xff; + b = b * a / 0xff; + } + + *p = (uint32_t)a << 24 | r << 16 | g << 8 | b; + } + } + } + pix = pixman_image_create_bits_no_clear( format, width, height, (uint32_t *)image_data, stride); |