Support transparency for ImageMagick images.
authorChong Yidong <cyd@gnu.org>
Mon, 11 Jun 2012 14:42:55 +0000 (22:42 +0800)
committerChong Yidong <cyd@gnu.org>
Mon, 11 Jun 2012 14:42:55 +0000 (22:42 +0800)
* src/image.c (imagemagick_load_image): Implement transparency.

* doc/lispref/display.texi (ImageMagick Images): ImageMagick now supports the
:background property.

doc/lispref/ChangeLog
doc/lispref/display.texi
etc/NEWS
src/ChangeLog
src/image.c

index 74c4a91..37221d7 100644 (file)
@@ -1,3 +1,8 @@
+2012-06-11  Chong Yidong  <cyd@gnu.org>
+
+       * display.texi (ImageMagick Images): ImageMagick now supports the
+       :background property.
+
 2012-06-10  Dmitry Antipov  <dmantipov@yandex.ru>
 
        * internals.texi (Garbage Collection): Typo fix.
index 3725b6f..5face41 100644 (file)
@@ -4603,6 +4603,12 @@ JPEG files, add @code{JPG} to this list.
 image descriptor properties:
 
 @table @code
+@item :background @var{background}
+@var{background}, if non-@code{nil}, should be a string specifying a
+color, which is used as the image's background color if the image
+supports transparency.  If the value is @code{nil}, it defaults to the
+frame's background color.
+
 @item :width, :height
 The @code{:width} and @code{:height} keywords are used for scaling the
 image.  If only one of them is specified, the other one will be
index 4c6df5c..85f4c31 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -80,6 +80,9 @@ ImageMagick types are treated as images.  The function
 `imagemagick-filter-types' returns the list of types that will be
 treated as images.
 
+*** Images displayed via ImageMagick now support transparency and the
+:background image spec property.
+
 ** String values for `initial-buffer-choice' also apply to emacsclient
 frames, if emacsclient is only told to open a new frame without
 specifying any file to visit or expression to evaluate.
index 919dcc1..1aba191 100644 (file)
@@ -1,3 +1,7 @@
+2012-06-11  Chong Yidong  <cyd@gnu.org>
+
+       * image.c (imagemagick_load_image): Implement transparency.
+
 2012-06-10  Andreas Schwab  <schwab@linux-m68k.org>
 
        * regex.c (at_begline_loc_p): Also recognize `(?N:' and correctly
index b6cdb6c..15fd7bb 100644 (file)
@@ -7599,19 +7599,14 @@ imagemagick_load_image (struct frame *f, struct image *img,
                        unsigned char *contents, unsigned int size,
                        char *filename)
 {
-  size_t width;
-  size_t height;
-
+  size_t width, height;
   MagickBooleanType status;
-
   XImagePtr ximg;
-  int x;
-  int y;
-
-  MagickWand  *image_wand;
-  MagickWand  *ping_wand;
+  int x, y;
+  MagickWand *image_wand;
+  MagickWand *ping_wand;
   PixelIterator *iterator;
-  PixelWand  **pixels;
+  PixelWand **pixels, *bg_wand = NULL;
   MagickPixelPacket  pixel;
   Lisp_Object image;
   Lisp_Object value;
@@ -7620,10 +7615,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
   int desired_width, desired_height;
   double rotation;
   int pixelwidth;
-  ImageInfo  *image_info;
-  ExceptionInfo *exception;
-  Image * im_image;
-
 
   /* Handle image index for image types who can contain more than one image.
      Interface :index is same as for GIF.  First we "ping" the image to see how
@@ -7637,14 +7628,9 @@ imagemagick_load_image (struct frame *f, struct image *img,
   ping_wand = NewMagickWand ();
   /* MagickSetResolution (ping_wand, 2, 2);   (Bug#10112)  */
 
-  if (filename != NULL)
-    {
-      status = MagickPingImage (ping_wand, filename);
-    }
-  else
-    {
-      status = MagickPingImageBlob (ping_wand, contents, size);
-    }
+  status = filename
+    ? MagickPingImage (ping_wand, filename)
+    : MagickPingImageBlob (ping_wand, contents, size);
 
   if (status == MagickFalse)
     {
@@ -7653,7 +7639,7 @@ imagemagick_load_image (struct frame *f, struct image *img,
       return 0;
     }
 
-  if (! (0 <= ino && ino < MagickGetNumberImages (ping_wand)))
+  if (ino < 0 || ino >= MagickGetNumberImages (ping_wand))
     {
       image_error ("Invalid image number `%s' in image `%s'",
                   image, img->spec);
@@ -7670,39 +7656,46 @@ imagemagick_load_image (struct frame *f, struct image *img,
   DestroyMagickWand (ping_wand);
 
   /* Now we know how many images are inside the file.  If it's not a
-     bundle, the number is one.  */
-
-  if (filename != NULL)
-    {
-      image_info = CloneImageInfo ((ImageInfo *) NULL);
-      (void) strcpy (image_info->filename, filename);
-      image_info->number_scenes = 1;
-      image_info->scene = ino;
-      exception = AcquireExceptionInfo ();
+     bundle, the number is one.  Load the image data.  */
 
-      im_image = ReadImage (image_info, exception);
-      DestroyExceptionInfo (exception);
+  image_wand = NewMagickWand ();
 
-      if (im_image == NULL)
-       goto imagemagick_no_wand;
-      image_wand = NewMagickWandFromImage (im_image);
-      DestroyImage (im_image);
-    }
-  else
+  if ((filename
+       ? MagickReadImage (image_wand, filename)
+       : MagickReadImageBlob (image_wand, contents, size))
+      == MagickFalse)
     {
-      image_wand = NewMagickWand ();
-      if (MagickReadImageBlob (image_wand, contents, size) == MagickFalse)
-       {
-         imagemagick_error (image_wand);
-         goto imagemagick_error;
-       }
+      imagemagick_error (image_wand);
+      goto imagemagick_error;
     }
 
+  /* Retrieve the frame's background color, for use later.  */
+  {
+    XColor bgcolor;
+    Lisp_Object specified_bg;
+
+    specified_bg = image_spec_value (img->spec, QCbackground, NULL);
+    if (!STRINGP (specified_bg)
+       || !x_defined_color (f, SSDATA (specified_bg), &bgcolor, 0))
+      {
+#ifndef HAVE_NS
+       bgcolor.pixel = FRAME_BACKGROUND_PIXEL (f);
+       x_query_color (f, &bgcolor);
+#else
+       ns_query_color (FRAME_BACKGROUND_COLOR (f), &bgcolor, 1);
+#endif
+      }
+
+    bg_wand = NewPixelWand ();
+    PixelSetRed   (bg_wand, (double) bgcolor.red   / 65535);
+    PixelSetGreen (bg_wand, (double) bgcolor.green / 65535);
+    PixelSetBlue  (bg_wand, (double) bgcolor.blue  / 65535);
+  }
+
   /* If width and/or height is set in the display spec assume we want
      to scale to those values.  If either h or w is unspecified, the
      unspecified should be calculated from the specified to preserve
      aspect ratio.  */
-
   value = image_spec_value (img->spec, QCwidth, NULL);
   desired_width = (INTEGERP (value)  ? XFASTINT (value) : -1);
   value = image_spec_value (img->spec, QCheight, NULL);
@@ -7768,13 +7761,8 @@ imagemagick_load_image (struct frame *f, struct image *img,
   value = image_spec_value (img->spec, QCrotation, NULL);
   if (FLOATP (value))
     {
-      PixelWand* background = NewPixelWand ();
-      PixelSetColor (background, "#ffffff");/*TODO remove hardcode*/
-
       rotation = extract_float (value);
-
-      status = MagickRotateImage (image_wand, background, rotation);
-      DestroyPixelWand (background);
+      status = MagickRotateImage (image_wand, bg_wand, rotation);
       if (status == MagickFalse)
         {
           image_error ("Imagemagick image rotate failed", Qnil, Qnil);
@@ -7788,6 +7776,18 @@ imagemagick_load_image (struct frame *f, struct image *img,
   height = MagickGetImageHeight (image_wand);
   width = MagickGetImageWidth (image_wand);
 
+  /* Set the canvas background color to the frame or specified
+     background, and flatten the image.  Note: as of ImageMagick
+     6.6.0, SVG image transparency is not handled properly
+     (e.g. etc/images/splash.svg shows a white background always).  */
+  {
+    MagickWand *new_wand;
+    MagickSetImageBackgroundColor (image_wand, bg_wand);
+    new_wand = MagickMergeImageLayers (image_wand, MergeLayer);
+    DestroyMagickWand (image_wand);
+    image_wand = new_wand;
+  }
+
   if (! (width <= INT_MAX && height <= INT_MAX
         && check_image_size (f, width, height)))
     {
@@ -7895,7 +7895,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
                               width, height,
                               exportdepth,
                               pixelwidth,
-                              /*&(img->pixmap));*/
                               ximg->data);
 #else
       image_error ("You don't have MagickExportImagePixels, upgrade ImageMagick!",
@@ -7910,7 +7909,6 @@ imagemagick_load_image (struct frame *f, struct image *img,
   free_color_table ();
 #endif /* COLOR_TABLE_SUPPORT */
 
-
   img->width  = width;
   img->height = height;
 
@@ -7919,9 +7917,10 @@ imagemagick_load_image (struct frame *f, struct image *img,
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
 
-
   /* Final cleanup. image_wand should be the only resource left. */
   DestroyMagickWand (image_wand);
+  if (bg_wand) DestroyPixelWand (bg_wand);
+
   /* `MagickWandTerminus' terminates the imagemagick environment.  */
   MagickWandTerminus ();
 
@@ -7929,6 +7928,8 @@ imagemagick_load_image (struct frame *f, struct image *img,
 
  imagemagick_error:
   DestroyMagickWand (image_wand);
+  if (bg_wand) DestroyPixelWand (bg_wand);
+
  imagemagick_no_wand:
   MagickWandTerminus ();
   /* TODO more cleanup.  */