From 1b9b4cf4c1152f06153ac9c141fb9f724b984884 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Mon, 11 Jun 2012 22:42:55 +0800 Subject: [PATCH] Support transparency for ImageMagick images. * src/image.c (imagemagick_load_image): Implement transparency. * doc/lispref/display.texi (ImageMagick Images): ImageMagick now supports the :background property. --- doc/lispref/ChangeLog | 5 ++ doc/lispref/display.texi | 6 +++ etc/NEWS | 3 ++ src/ChangeLog | 4 ++ src/image.c | 113 ++++++++++++++++++++------------------- 5 files changed, 75 insertions(+), 56 deletions(-) diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 74c4a91c49..37221d7410 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,8 @@ +2012-06-11 Chong Yidong + + * display.texi (ImageMagick Images): ImageMagick now supports the + :background property. + 2012-06-10 Dmitry Antipov * internals.texi (Garbage Collection): Typo fix. diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 3725b6fd82..5face4138e 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -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 diff --git a/etc/NEWS b/etc/NEWS index 4c6df5c09c..85f4c31f07 100644 --- 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. diff --git a/src/ChangeLog b/src/ChangeLog index 919dcc1009..1aba1913f4 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2012-06-11 Chong Yidong + + * image.c (imagemagick_load_image): Implement transparency. + 2012-06-10 Andreas Schwab * regex.c (at_begline_loc_p): Also recognize `(?N:' and correctly diff --git a/src/image.c b/src/image.c index b6cdb6c829..15fd7bbeab 100644 --- a/src/image.c +++ b/src/image.c @@ -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. */ -- 2.20.1