changeset 70168:60bff6b0c656

(four_corners_best): New arg CORNERS specifies what pixels to look at in case image has margin. (x_create_bitmap_mask): Pass NULL for CORNERS to four_corners_best. (image_background, image_background_transparent) (x_build_heuristic_mask): Pass img->corners to four_corners_best. (gif_load): Set img->corners according to image's margin spec. Use img->corners values directly where applicable. Save image extension data in img->data.lisp_val. (gif_clear_image): New function to free img->data.lisp_val. (gif_type): Use it instead of generic x_clear_image. (Fimage_extension_data): New defun. (syms_of_image): Defsubr it.
author Kim F. Storm <storm@cua.dk>
date Fri, 21 Apr 2006 14:07:05 +0000
parents fd8a5c0f1290
children 10be49d855c4
files src/image.c
diffstat 1 files changed, 102 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/src/image.c	Fri Apr 21 14:06:55 2006 +0000
+++ b/src/image.c	Fri Apr 21 14:07:05 2006 +0000
@@ -603,7 +603,9 @@
 /* Useful functions defined in the section
    `Image type independent image structures' below. */
 
-static unsigned long four_corners_best P_ ((XImagePtr ximg, unsigned long width,
+static unsigned long four_corners_best P_ ((XImagePtr ximg,
+					    int *corners,
+					    unsigned long width,
 					    unsigned long height));
 
 static int x_create_x_image_and_pixmap P_ ((struct frame *f, int width, int height,
@@ -657,7 +659,7 @@
       return -1;
     }
 
-  bg = four_corners_best (ximg, width, height);
+  bg = four_corners_best (ximg, NULL, width, height);
 
   for (y = 0; y < ximg->height; ++y)
     {
@@ -732,7 +734,7 @@
 /* Keywords.  */
 
 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
-extern Lisp_Object QCdata, QCtype;
+extern Lisp_Object QCdata, QCtype, Qcount;
 extern Lisp_Object Qcenter;
 Lisp_Object QCascent, QCmargin, QCrelief;
 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
@@ -1141,6 +1143,27 @@
   return mask;
 }
 
+DEFUN ("image-extension-data", Fimage_extension_data, Simage_extension_data, 1, 2, 0,
+       doc: /* Return extension data for image SPEC.
+FRAME is the frame on which the image will be displayed.  FRAME nil
+or omitted means use the selected frame.  */)
+     (spec, frame)
+     Lisp_Object spec, frame;
+{
+  Lisp_Object ext;
+
+  ext = Qnil;
+  if (valid_image_p (spec))
+    {
+      struct frame *f = check_x_frame (frame);
+      int id = lookup_image (f, spec);
+      struct image *img = IMAGE_FROM_ID (f, id);
+      ext = img->data.lisp_val;
+    }
+
+  return ext;
+}
+
 
 /***********************************************************************
 		 Image type independent image structures
@@ -1171,6 +1194,7 @@
   img->data.lisp_val = Qnil;
   img->ascent = DEFAULT_IMAGE_ASCENT;
   img->hash = hash;
+  img->corners[BOT_CORNER] = -1;  /* Full image */
   return img;
 }
 
@@ -1322,30 +1346,41 @@
    On W32, XIMG is assumed to a device context with the bitmap selected.  */
 
 static RGB_PIXEL_COLOR
-four_corners_best (ximg, width, height)
+four_corners_best (ximg, corners, width, height)
      XImagePtr_or_DC ximg;
+     int *corners;
      unsigned long width, height;
 {
-  RGB_PIXEL_COLOR corners[4], best;
+  RGB_PIXEL_COLOR corner_pixels[4], best;
   int i, best_count;
 
-  /* Get the colors at the corners of ximg.  */
-  corners[0] = GET_PIXEL (ximg, 0, 0);
-  corners[1] = GET_PIXEL (ximg, width - 1, 0);
-  corners[2] = GET_PIXEL (ximg, width - 1, height - 1);
-  corners[3] = GET_PIXEL (ximg, 0, height - 1);
-
+  if (corners && corners[BOT_CORNER] >= 0)
+    {
+      /* Get the colors at the corner_pixels of ximg.  */
+      corner_pixels[0] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[TOP_CORNER]);
+      corner_pixels[1] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[TOP_CORNER]);
+      corner_pixels[2] = GET_PIXEL (ximg, corners[RIGHT_CORNER] - 1, corners[BOT_CORNER] - 1);
+      corner_pixels[3] = GET_PIXEL (ximg, corners[LEFT_CORNER], corners[BOT_CORNER] - 1);
+    }
+  else
+    {
+      /* Get the colors at the corner_pixels of ximg.  */
+      corner_pixels[0] = GET_PIXEL (ximg, 0, 0);
+      corner_pixels[1] = GET_PIXEL (ximg, width - 1, 0);
+      corner_pixels[2] = GET_PIXEL (ximg, width - 1, height - 1);
+      corner_pixels[3] = GET_PIXEL (ximg, 0, height - 1);
+    }
   /* Choose the most frequently found color as background.  */
   for (i = best_count = 0; i < 4; ++i)
     {
       int j, n;
 
       for (j = n = 0; j < 4; ++j)
-	if (corners[i] == corners[j])
+	if (corner_pixels[i] == corner_pixels[j])
 	  ++n;
 
       if (n > best_count)
-	best = corners[i], best_count = n;
+	best = corner_pixels[i], best_count = n;
     }
 
   return best;
@@ -1404,7 +1439,7 @@
 #endif /* !HAVE_NTGUI */
 	}
 
-      img->background = four_corners_best (ximg, img->width, img->height);
+      img->background = four_corners_best (ximg, img->corners, img->width, img->height);
 
       if (free_ximg)
 	Destroy_Image (ximg, prev);
@@ -1449,7 +1484,7 @@
 	    }
 
 	  img->background_transparent
-	    = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN);
+	    = (four_corners_best (mask, img->corners, img->width, img->height) == PIX_MASK_RETAIN);
 
 	  if (free_mask)
 	    Destroy_Image (mask, prev);
@@ -5358,7 +5393,7 @@
     }
 
   if (use_img_background)
-    bg = four_corners_best (ximg, img->width, img->height);
+    bg = four_corners_best (ximg, img->corners, img->width, img->height);
 
   /* Set all bits in mask_img to 1 whose color in ximg is different
      from the background color bg.  */
@@ -7451,6 +7486,7 @@
 
 static int gif_image_p P_ ((Lisp_Object object));
 static int gif_load P_ ((struct frame *f, struct image *img));
+static void gif_clear_image P_ ((struct frame *f, struct image *img));
 
 /* The symbol `gif' identifying images of this type.  */
 
@@ -7499,10 +7535,22 @@
   &Qgif,
   gif_image_p,
   gif_load,
-  x_clear_image,
+  gif_clear_image,
   NULL
 };
 
+/* Free X resources of GIF image IMG which is used on frame F.  */
+
+static void
+gif_clear_image (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  /* IMG->data.ptr_val may contain extension data.  */
+  img->data.lisp_val = Qnil;
+  x_clear_image (f, img);
+}
+
 /* Return non-zero if OBJECT is a valid GIF image specification.  */
 
 static int
@@ -7623,7 +7671,7 @@
   GifFileType *gif;
   struct gcpro gcpro1;
   Lisp_Object image;
-  int ino, image_left, image_top, image_width, image_height;
+  int ino, image_height, image_width;
   gif_memory_source memsrc;
   unsigned char *raster;
 
@@ -7700,17 +7748,19 @@
       return 0;
     }
 
-  image_top = gif->SavedImages[ino].ImageDesc.Top;
-  image_left = gif->SavedImages[ino].ImageDesc.Left;
+  img->corners[TOP_CORNER] = gif->SavedImages[ino].ImageDesc.Top;
+  img->corners[LEFT_CORNER] = gif->SavedImages[ino].ImageDesc.Left;
+  image_height = gif->SavedImages[ino].ImageDesc.Height;
+  img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + image_height;
   image_width = gif->SavedImages[ino].ImageDesc.Width;
-  image_height = gif->SavedImages[ino].ImageDesc.Height;
+  img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + image_width;
 
   width = img->width = max (gif->SWidth,
 			    max (gif->Image.Left + gif->Image.Width,
-				 image_left + image_width));
+				 img->corners[RIGHT_CORNER]));
   height = img->height = max (gif->SHeight,
 			      max (gif->Image.Top + gif->Image.Height,
-				   image_top + image_height));
+				   img->corners[BOT_CORNER]));
 
   if (!check_image_size (f, width, height))
     {
@@ -7753,19 +7803,19 @@
      requires more than can be done here (see the gif89 spec,
      disposal methods).  Let's simply assume that the part
      not covered by a sub-image is in the frame's background color.  */
-  for (y = 0; y < image_top; ++y)
+  for (y = 0; y < img->corners[TOP_CORNER]; ++y)
     for (x = 0; x < width; ++x)
       XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
 
-  for (y = image_top + image_height; y < height; ++y)
+  for (y = img->corners[BOT_CORNER]; y < height; ++y)
     for (x = 0; x < width; ++x)
       XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
 
-  for (y = image_top; y < image_top + image_height; ++y)
-    {
-      for (x = 0; x < image_left; ++x)
+  for (y = img->corners[TOP_CORNER]; y < img->corners[BOT_CORNER]; ++y)
+    {
+      for (x = 0; x < img->corners[LEFT_CORNER]; ++x)
 	XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
-      for (x = image_left + image_width; x < width; ++x)
+      for (x = img->corners[RIGHT_CORNER]; x < width; ++x)
 	XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
     }
 
@@ -7795,8 +7845,8 @@
 	  for (x = 0; x < image_width; x++)
 	    {
 	      int i = raster[(y * image_width) + x];
-	      XPutPixel (ximg, x + image_left, row + image_top,
-			 pixel_colors[i]);
+	      XPutPixel (ximg, x + img->corners[LEFT_CORNER],
+			 row + img->corners[TOP_CORNER], pixel_colors[i]);
 	    }
 
 	  row += interlace_increment[pass];
@@ -7808,10 +7858,29 @@
 	for (x = 0; x < image_width; ++x)
 	  {
 	    int i = raster[y * image_width + x];
-	    XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
+	    XPutPixel (ximg, x + img->corners[LEFT_CORNER],
+		       y + img->corners[TOP_CORNER], pixel_colors[i]);
 	  }
     }
 
+  /* Save GIF image extension data for `image-extension-data'.
+     Format is (count IMAGES FUNCTION "BYTES" ...).  */
+  img->data.lisp_val = Qnil;
+  if (gif->SavedImages[ino].ExtensionBlockCount > 0)
+    {
+      ExtensionBlock *ext = gif->SavedImages[ino].ExtensionBlocks;
+      for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++, ext++)
+	/* Append (... FUNCTION "BYTES") */
+	img->data.lisp_val = Fcons (make_unibyte_string (ext->Bytes, ext->ByteCount),
+				    Fcons (make_number (ext->Function),
+					   img->data.lisp_val));
+      img->data.lisp_val = Fnreverse (img->data.lisp_val);
+    }
+  if (gif->ImageCount > 1)
+    img->data.lisp_val = Fcons (Qcount,
+				Fcons (make_number (gif->ImageCount),
+				       img->data.lisp_val));
+
   fn_DGifCloseFile (gif);
 
   /* Maybe fill in the background field while we have ximg handy. */
@@ -8557,6 +8626,7 @@
   defsubr (&Sclear_image_cache);
   defsubr (&Simage_size);
   defsubr (&Simage_mask_p);
+  defsubr (&Simage_extension_data);
 
 #if GLYPH_DEBUG
   defsubr (&Simagep);