diff options
| author | Stefan Kangas | 2023-08-25 20:26:45 +0200 |
|---|---|---|
| committer | Stefan Kangas | 2023-08-25 20:26:59 +0200 |
| commit | eb61bbacef76ff10b47008711529f8c0b18ea993 (patch) | |
| tree | 5b253d6bc6b56ac651e86bf6080cbf5feb41fb1c /src | |
| parent | aaaee4ebe198d810a2e62a38bee49fc2ee2cfcbd (diff) | |
| download | emacs-eb61bbacef76ff10b47008711529f8c0b18ea993.tar.gz emacs-eb61bbacef76ff10b47008711529f8c0b18ea993.zip | |
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)
Diffstat (limited to 'src')
| -rw-r--r-- | src/image.c | 72 |
1 files changed, 38 insertions, 34 deletions
diff --git a/src/image.c b/src/image.c index 7019bbf31be..70dd280b5dd 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -10450,22 +10450,36 @@ webp_load (struct frame *f, struct image *img) | |||
| 10450 | } | 10450 | } |
| 10451 | 10451 | ||
| 10452 | /* Create the x image and pixmap. */ | 10452 | /* Create the x image and pixmap. */ |
| 10453 | Emacs_Pix_Container ximg, mask_img = NULL; | 10453 | Emacs_Pix_Container ximg; |
| 10454 | if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, false)) | 10454 | if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, false)) |
| 10455 | goto webp_error2; | 10455 | goto webp_error2; |
| 10456 | 10456 | ||
| 10457 | /* Create an image and pixmap serving as mask if the WebP image | 10457 | /* Find the background to use if the WebP image contains an alpha |
| 10458 | contains an alpha channel. */ | 10458 | channel. */ |
| 10459 | if (features.has_alpha | 10459 | Emacs_Color bg_color; |
| 10460 | && !image_create_x_image_and_pixmap (f, img, width, height, 1, | 10460 | if (features.has_alpha) |
| 10461 | &mask_img, true)) | ||
| 10462 | { | 10461 | { |
| 10463 | image_destroy_x_image (ximg); | 10462 | Lisp_Object specified_bg |
| 10464 | image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP); | 10463 | = image_spec_value (img->spec, QCbackground, NULL); |
| 10465 | goto webp_error2; | 10464 | |
| 10465 | /* If the user specified a color, try to use it; if not, use the | ||
| 10466 | current frame background, ignoring any default background | ||
| 10467 | color set by the image. */ | ||
| 10468 | if (STRINGP (specified_bg)) | ||
| 10469 | FRAME_TERMINAL (f)->defined_color_hook (f, | ||
| 10470 | SSDATA (specified_bg), | ||
| 10471 | &bg_color, | ||
| 10472 | false, | ||
| 10473 | false); | ||
| 10474 | else | ||
| 10475 | FRAME_TERMINAL (f)->query_frame_background_color (f, &bg_color); | ||
| 10476 | bg_color.red >>= 8; | ||
| 10477 | bg_color.green >>= 8; | ||
| 10478 | bg_color.blue >>= 8; | ||
| 10466 | } | 10479 | } |
| 10467 | 10480 | ||
| 10468 | /* Fill the X image and mask from WebP data. */ | 10481 | /* Fill the X image from WebP data. */ |
| 10482 | |||
| 10469 | init_color_table (); | 10483 | init_color_table (); |
| 10470 | 10484 | ||
| 10471 | img->corners[TOP_CORNER] = 0; | 10485 | img->corners[TOP_CORNER] = 0; |
| @@ -10480,21 +10494,21 @@ webp_load (struct frame *f, struct image *img) | |||
| 10480 | { | 10494 | { |
| 10481 | for (int x = 0; x < width; ++x) | 10495 | for (int x = 0; x < width; ++x) |
| 10482 | { | 10496 | { |
| 10483 | int r = *p++ << 8; | 10497 | int r, g, b; |
| 10484 | int g = *p++ << 8; | 10498 | /* The WebP alpha channel allows 256 levels of partial |
| 10485 | int b = *p++ << 8; | 10499 | transparency. Blend it with the background manually. */ |
| 10500 | if (features.has_alpha || anim) { | ||
| 10501 | float a = (float) p[3] / UINT8_MAX; | ||
| 10502 | r = (int)(a * p[0] + (1.0 - a) * bg_color.red) << 8; | ||
| 10503 | g = (int)(a * p[1] + (1.0 - a) * bg_color.green) << 8; | ||
| 10504 | b = (int)(a * p[2] + (1.0 - a) * bg_color.blue) << 8; | ||
| 10505 | p += 4; | ||
| 10506 | } else { | ||
| 10507 | r = *p++ << 8; | ||
| 10508 | g = *p++ << 8; | ||
| 10509 | b = *p++ << 8; | ||
| 10510 | } | ||
| 10486 | PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b)); | 10511 | PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b)); |
| 10487 | |||
| 10488 | /* An alpha channel associates variable transparency with an | ||
| 10489 | image. WebP allows up to 256 levels of partial transparency. | ||
| 10490 | We handle this like with PNG (which see), using the frame's | ||
| 10491 | background color to combine the image with. */ | ||
| 10492 | if (features.has_alpha || anim) | ||
| 10493 | { | ||
| 10494 | if (mask_img) | ||
| 10495 | PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN); | ||
| 10496 | ++p; | ||
| 10497 | } | ||
| 10498 | } | 10512 | } |
| 10499 | } | 10513 | } |
| 10500 | 10514 | ||
| @@ -10507,16 +10521,6 @@ webp_load (struct frame *f, struct image *img) | |||
| 10507 | /* Put ximg into the image. */ | 10521 | /* Put ximg into the image. */ |
| 10508 | image_put_x_image (f, img, ximg, 0); | 10522 | image_put_x_image (f, img, ximg, 0); |
| 10509 | 10523 | ||
| 10510 | /* Same for the mask. */ | ||
| 10511 | if (mask_img) | ||
| 10512 | { | ||
| 10513 | /* Fill in the background_transparent field while we have the | ||
| 10514 | mask handy. Casting avoids a GCC warning. */ | ||
| 10515 | image_background_transparent (img, f, (Emacs_Pix_Context)mask_img); | ||
| 10516 | |||
| 10517 | image_put_x_image (f, img, mask_img, 1); | ||
| 10518 | } | ||
| 10519 | |||
| 10520 | img->width = width; | 10524 | img->width = width; |
| 10521 | img->height = height; | 10525 | img->height = height; |
| 10522 | 10526 | ||