]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix alpha blending for WebP images
authorStefan Kangas <stefankangas@gmail.com>
Fri, 25 Aug 2023 18:26:45 +0000 (20:26 +0200)
committerStefan Kangas <stefankangas@gmail.com>
Fri, 25 Aug 2023 18:26:59 +0000 (20:26 +0200)
* src/image.c (webp_load): Fix WebP transparency by doing manual alpha
blending instead of naive masking.  (Bug#59242)

src/image.c

index 7019bbf31be773e795cddbc08ef1a44d45fec6a1..70dd280b5dd8a7c507bffd5a4237b1d45ae89028 100644 (file)
@@ -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;