Fix alpha blending for WebP images
* src/image.c (webp_load): Fix WebP transparency by doing manual alpha blending instead of naive masking. (Bug#59242)
This commit is contained in:
parent
aaaee4ebe1
commit
eb61bbacef
1 changed files with 38 additions and 34 deletions
72
src/image.c
72
src/image.c
|
@ -10450,22 +10450,36 @@ webp_load (struct frame *f, struct image *img)
|
|||
}
|
||||
|
||||
/* Create the x image and pixmap. */
|
||||
Emacs_Pix_Container ximg, mask_img = NULL;
|
||||
Emacs_Pix_Container ximg;
|
||||
if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, false))
|
||||
goto webp_error2;
|
||||
|
||||
/* Create an image and pixmap serving as mask if the WebP image
|
||||
contains an alpha channel. */
|
||||
if (features.has_alpha
|
||||
&& !image_create_x_image_and_pixmap (f, img, width, height, 1,
|
||||
&mask_img, true))
|
||||
/* Find the background to use if the WebP image contains an alpha
|
||||
channel. */
|
||||
Emacs_Color bg_color;
|
||||
if (features.has_alpha)
|
||||
{
|
||||
image_destroy_x_image (ximg);
|
||||
image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
|
||||
goto webp_error2;
|
||||
Lisp_Object specified_bg
|
||||
= image_spec_value (img->spec, QCbackground, NULL);
|
||||
|
||||
/* If the user specified a color, try to use it; if not, use the
|
||||
current frame background, ignoring any default background
|
||||
color set by the image. */
|
||||
if (STRINGP (specified_bg))
|
||||
FRAME_TERMINAL (f)->defined_color_hook (f,
|
||||
SSDATA (specified_bg),
|
||||
&bg_color,
|
||||
false,
|
||||
false);
|
||||
else
|
||||
FRAME_TERMINAL (f)->query_frame_background_color (f, &bg_color);
|
||||
bg_color.red >>= 8;
|
||||
bg_color.green >>= 8;
|
||||
bg_color.blue >>= 8;
|
||||
}
|
||||
|
||||
/* Fill the X image and mask from WebP data. */
|
||||
/* Fill the X image from WebP data. */
|
||||
|
||||
init_color_table ();
|
||||
|
||||
img->corners[TOP_CORNER] = 0;
|
||||
|
@ -10480,21 +10494,21 @@ webp_load (struct frame *f, struct image *img)
|
|||
{
|
||||
for (int x = 0; x < width; ++x)
|
||||
{
|
||||
int r = *p++ << 8;
|
||||
int g = *p++ << 8;
|
||||
int b = *p++ << 8;
|
||||
int r, g, b;
|
||||
/* The WebP alpha channel allows 256 levels of partial
|
||||
transparency. Blend it with the background manually. */
|
||||
if (features.has_alpha || anim) {
|
||||
float a = (float) p[3] / UINT8_MAX;
|
||||
r = (int)(a * p[0] + (1.0 - a) * bg_color.red) << 8;
|
||||
g = (int)(a * p[1] + (1.0 - a) * bg_color.green) << 8;
|
||||
b = (int)(a * p[2] + (1.0 - a) * bg_color.blue) << 8;
|
||||
p += 4;
|
||||
} else {
|
||||
r = *p++ << 8;
|
||||
g = *p++ << 8;
|
||||
b = *p++ << 8;
|
||||
}
|
||||
PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
|
||||
|
||||
/* An alpha channel associates variable transparency with an
|
||||
image. WebP allows up to 256 levels of partial transparency.
|
||||
We handle this like with PNG (which see), using the frame's
|
||||
background color to combine the image with. */
|
||||
if (features.has_alpha || anim)
|
||||
{
|
||||
if (mask_img)
|
||||
PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10507,16 +10521,6 @@ webp_load (struct frame *f, struct image *img)
|
|||
/* Put ximg into the image. */
|
||||
image_put_x_image (f, img, ximg, 0);
|
||||
|
||||
/* Same for the mask. */
|
||||
if (mask_img)
|
||||
{
|
||||
/* Fill in the background_transparent field while we have the
|
||||
mask handy. Casting avoids a GCC warning. */
|
||||
image_background_transparent (img, f, (Emacs_Pix_Context)mask_img);
|
||||
|
||||
image_put_x_image (f, img, mask_img, 1);
|
||||
}
|
||||
|
||||
img->width = width;
|
||||
img->height = height;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue