X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/067a69a2d38db30190997dc48dbf82988ffa3583..437b2cb453cedf1a9033b2082879f1964c67ed23:/src/image.c diff --git a/src/image.c b/src/image.c index 2562d79a78..6e8440fb43 100644 --- a/src/image.c +++ b/src/image.c @@ -182,20 +182,20 @@ XPutPixel (XImagePtr ximage, int x, int y, unsigned long pixel) /* Functions to access the contents of a bitmap, given an id. */ int -x_bitmap_height (FRAME_PTR f, int id) +x_bitmap_height (FRAME_PTR f, ptrdiff_t id) { return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].height; } int -x_bitmap_width (FRAME_PTR f, int id) +x_bitmap_width (FRAME_PTR f, ptrdiff_t id) { return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].width; } #if defined (HAVE_X_WINDOWS) || defined (HAVE_NTGUI) int -x_bitmap_pixmap (FRAME_PTR f, int id) +x_bitmap_pixmap (FRAME_PTR f, ptrdiff_t id) { return (int) FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap; } @@ -203,7 +203,7 @@ x_bitmap_pixmap (FRAME_PTR f, int id) #ifdef HAVE_X_WINDOWS int -x_bitmap_mask (FRAME_PTR f, int id) +x_bitmap_mask (FRAME_PTR f, ptrdiff_t id) { return FRAME_X_DISPLAY_INFO (f)->bitmaps[id - 1].mask; } @@ -211,11 +211,11 @@ x_bitmap_mask (FRAME_PTR f, int id) /* Allocate a new bitmap record. Returns index of new record. */ -static int +static ptrdiff_t x_allocate_bitmap_record (FRAME_PTR f) { Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - int i; + ptrdiff_t i; if (dpyinfo->bitmaps == NULL) { @@ -233,6 +233,9 @@ x_allocate_bitmap_record (FRAME_PTR f) if (dpyinfo->bitmaps[i].refcount == 0) return i + 1; + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (Bitmap_Record) / 2 + < dpyinfo->bitmaps_size) + memory_full (SIZE_MAX); dpyinfo->bitmaps_size *= 2; dpyinfo->bitmaps = (Bitmap_Record *) xrealloc (dpyinfo->bitmaps, @@ -250,11 +253,11 @@ x_reference_bitmap (FRAME_PTR f, int id) /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */ -int +ptrdiff_t x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsigned int height) { Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - int id; + ptrdiff_t id; #ifdef HAVE_X_WINDOWS Pixmap bitmap; @@ -309,7 +312,7 @@ x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsi /* Create bitmap from file FILE for frame F. */ -int +ptrdiff_t x_create_bitmap_from_file (struct frame *f, Lisp_Object file) { Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); @@ -319,7 +322,7 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file) #endif /* HAVE_NTGUI */ #ifdef HAVE_NS - int id; + ptrdiff_t id; void *bitmap = ns_image_from_file (file); if (!bitmap) @@ -340,7 +343,8 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file) #ifdef HAVE_X_WINDOWS unsigned int width, height; Pixmap bitmap; - int xhot, yhot, result, id; + int xhot, yhot, result; + ptrdiff_t id; Lisp_Object found; int fd; char *filename; @@ -413,7 +417,7 @@ free_bitmap_record (Display_Info *dpyinfo, Bitmap_Record *bm) /* Remove reference to bitmap with id number ID. */ void -x_destroy_bitmap (FRAME_PTR f, int id) +x_destroy_bitmap (FRAME_PTR f, ptrdiff_t id) { Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); @@ -435,7 +439,7 @@ x_destroy_bitmap (FRAME_PTR f, int id) void x_destroy_all_bitmaps (Display_Info *dpyinfo) { - int i; + ptrdiff_t i; Bitmap_Record *bm = dpyinfo->bitmaps; for (i = 0; i < dpyinfo->bitmaps_last; i++, bm++) @@ -467,7 +471,7 @@ static void x_destroy_x_image (XImagePtr ximg); It's nicer with some borders in this context */ int -x_create_bitmap_mask (struct frame *f, int id) +x_create_bitmap_mask (struct frame *f, ptrdiff_t id) { Pixmap pixmap, mask; XImagePtr ximg, mask_img; @@ -564,7 +568,6 @@ static Lisp_Object Qxbm; /* Keywords. */ Lisp_Object QCascent, QCmargin, QCrelief; -static Lisp_Object Qcount, Qextension_data; Lisp_Object QCconversion; static Lisp_Object QCheuristic_mask; static Lisp_Object QCcolor_symbols; @@ -573,6 +576,7 @@ static Lisp_Object QCcrop, QCrotation; /* Other symbols. */ +static Lisp_Object Qcount, Qextension_data, Qdelay; static Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic; /* Function prototypes. */ @@ -623,7 +627,7 @@ define_image_type (struct image_type *type, int loaded) /* Look up image type SYMBOL, and return a pointer to its image_type structure. Value is null if SYMBOL is not a known image type. */ -static INLINE struct image_type * +static inline struct image_type * lookup_image_type (Lisp_Object symbol) { struct image_type *type; @@ -971,7 +975,7 @@ or omitted means use the selected frame. */) 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; + ext = img->lisp_data; } return ext; @@ -982,7 +986,6 @@ or omitted means use the selected frame. */) Image type independent image structures ***********************************************************************/ -static struct image *make_image (Lisp_Object spec, unsigned hash); static void free_image (struct frame *f, struct image *img); static int check_image_size (struct frame *f, int width, int height); @@ -991,7 +994,7 @@ static int check_image_size (struct frame *f, int width, int height); SPEC. SPEC has a hash value of HASH. */ static struct image * -make_image (Lisp_Object spec, unsigned int hash) +make_image (Lisp_Object spec, EMACS_UINT hash) { struct image *img = (struct image *) xmalloc (sizeof *img); Lisp_Object file = image_spec_value (spec, QCfile, NULL); @@ -1002,7 +1005,7 @@ make_image (Lisp_Object spec, unsigned int hash) img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL)); xassert (img->type != NULL); img->spec = spec; - img->data.lisp_val = Qnil; + img->lisp_data = Qnil; img->ascent = DEFAULT_IMAGE_ASCENT; img->hash = hash; img->corners[BOT_CORNER] = -1; /* Full image */ @@ -1388,7 +1391,6 @@ x_alloc_image_color (struct frame *f, struct image *img, Lisp_Object color_name, Image Cache ***********************************************************************/ -static struct image *search_image_cache (struct frame *, Lisp_Object, unsigned); static void cache_image (struct frame *f, struct image *img); static void postprocess_image (struct frame *, struct image *); @@ -1414,7 +1416,7 @@ make_image_cache (void) /* Find an image matching SPEC in the cache, and return it. If no image is found, return NULL. */ static struct image * -search_image_cache (struct frame *f, Lisp_Object spec, unsigned int hash) +search_image_cache (struct frame *f, Lisp_Object spec, EMACS_UINT hash) { struct image *img; struct image_cache *c = FRAME_IMAGE_CACHE (f); @@ -1714,7 +1716,7 @@ int lookup_image (struct frame *f, Lisp_Object spec) { struct image *img; - unsigned hash; + EMACS_UINT hash; EMACS_TIME now; /* F must be a window-system frame, and SPEC must be a valid image @@ -1834,6 +1836,8 @@ cache_image (struct frame *f, struct image *img) /* If no free slot found, maybe enlarge c->images. */ if (i == c->used && c->used == c->size) { + if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *c->images / 2 < c->size) + memory_full (SIZE_MAX); c->size *= 2; c->images = (struct image **) xrealloc (c->images, c->size * sizeof *c->images); @@ -1866,8 +1870,8 @@ mark_image (struct image *img) mark_object (img->spec); mark_object (img->dependencies); - if (!NILP (img->data.lisp_val)) - mark_object (img->data.lisp_val); + if (!NILP (img->lisp_data)) + mark_object (img->lisp_data); } @@ -2114,9 +2118,6 @@ x_put_x_image (struct frame *f, XImagePtr ximg, Pixmap pixmap, int width, int he File Handling ***********************************************************************/ -static unsigned char *slurp_file (char *, int *); - - /* Find image file FILE. Look in data-directory/images, then x-bitmap-file-path. Value is the encoded full name of the file found, or nil if not found. */ @@ -2153,7 +2154,7 @@ x_find_image_file (Lisp_Object file) occurred. *SIZE is set to the size of the file. */ static unsigned char * -slurp_file (char *file, int *size) +slurp_file (char *file, ptrdiff_t *size) { FILE *fp = NULL; unsigned char *buf = NULL; @@ -2161,6 +2162,7 @@ slurp_file (char *file, int *size) if (stat (file, &st) == 0 && (fp = fopen (file, "rb")) != NULL + && 0 <= st.st_size && st.st_size <= min (PTRDIFF_MAX, SIZE_MAX) && (buf = (unsigned char *) xmalloc (st.st_size), fread (buf, 1, st.st_size, fp) == st.st_size)) { @@ -2312,7 +2314,7 @@ xbm_image_p (Lisp_Object object) else { Lisp_Object data; - int width, height; + EMACS_INT width, height; /* Entries for `:width', `:height' and `:data' must be present. */ if (!kw[XBM_WIDTH].count @@ -2328,7 +2330,7 @@ xbm_image_p (Lisp_Object object) data. */ if (VECTORP (data)) { - int i; + EMACS_INT i; /* Number of elements of the vector must be >= height. */ if (ASIZE (data) < height) @@ -2816,7 +2818,7 @@ xbm_load (struct frame *f, struct image *img) { Lisp_Object file; unsigned char *contents; - int size; + ptrdiff_t size; file = x_find_image_file (file_name); if (!STRINGP (file)) @@ -2833,6 +2835,7 @@ xbm_load (struct frame *f, struct image *img) } success_p = xbm_load_image (f, img, contents, contents + size); + xfree (contents); } else { @@ -3285,11 +3288,12 @@ xpm_image_p (Lisp_Object object) #endif /* HAVE_XPM || HAVE_NS */ #if defined HAVE_XPM && defined HAVE_X_WINDOWS && !defined USE_GTK -int +ptrdiff_t x_create_bitmap_from_xpm_data (struct frame *f, const char **bits) { Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f); - int id, rc; + ptrdiff_t id; + int rc; XpmAttributes attrs; Pixmap bitmap, mask; @@ -3593,25 +3597,14 @@ xpm_load (struct frame *f, struct image *img) /* XPM support functions for NS where libxpm is not available. Only XPM version 3 (without any extensions) is supported. */ -static int xpm_scan (const unsigned char **, const unsigned char *, - const unsigned char **, int *); -static Lisp_Object xpm_make_color_table_v - (void (**) (Lisp_Object, const unsigned char *, int, Lisp_Object), - Lisp_Object (**) (Lisp_Object, const unsigned char *, int)); static void xpm_put_color_table_v (Lisp_Object, const unsigned char *, int, Lisp_Object); static Lisp_Object xpm_get_color_table_v (Lisp_Object, const unsigned char *, int); -static Lisp_Object xpm_make_color_table_h - (void (**) (Lisp_Object, const unsigned char *, int, Lisp_Object), - Lisp_Object (**) (Lisp_Object, const unsigned char *, int)); static void xpm_put_color_table_h (Lisp_Object, const unsigned char *, int, Lisp_Object); static Lisp_Object xpm_get_color_table_h (Lisp_Object, const unsigned char *, int); -static int xpm_str_to_color_key (const char *); -static int xpm_load_image (struct frame *, struct image *, - const unsigned char *, const unsigned char *); /* Tokens returned from xpm_scan. */ @@ -3633,7 +3626,7 @@ static int xpm_scan (const unsigned char **s, const unsigned char *end, const unsigned char **beg, - int *len) + ptrdiff_t *len) { int c; @@ -3751,7 +3744,7 @@ xpm_put_color_table_h (Lisp_Object color_table, Lisp_Object color) { struct Lisp_Hash_Table *table = XHASH_TABLE (color_table); - unsigned hash_code; + EMACS_UINT hash_code; Lisp_Object chars = make_unibyte_string (chars_start, chars_len); hash_lookup (table, chars, &hash_code); @@ -3803,7 +3796,8 @@ xpm_load_image (struct frame *f, unsigned char buffer[BUFSIZ]; int width, height, x, y; int num_colors, chars_per_pixel; - int len, LA1; + ptrdiff_t len; + int LA1; void (*put_color_table) (Lisp_Object, const unsigned char *, int, Lisp_Object); Lisp_Object (*get_color_table) (Lisp_Object, const unsigned char *, int); Lisp_Object frame, color_symbols, color_table; @@ -4041,7 +4035,7 @@ xpm_load (struct frame *f, { Lisp_Object file; unsigned char *contents; - int size; + ptrdiff_t size; file = x_find_image_file (file_name); if (!STRINGP (file)) @@ -5023,6 +5017,7 @@ pbm_read_file (file, size) if (stat (SDATA (file), &st) == 0 && (fp = fopen (SDATA (file), "rb")) != NULL + && 0 <= st.st_size && st.st_size <= min (PTRDIFF_MAX, SIZE_MAX) && (buf = (char *) xmalloc (st.st_size), fread (buf, 1, st.st_size, fp) == st.st_size)) { @@ -5057,7 +5052,7 @@ pbm_load (struct frame *f, struct image *img) enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type; unsigned char *contents = NULL; unsigned char *end, *p; - int size; + ptrdiff_t size; specified_file = image_spec_value (img->spec, QCfile, NULL); @@ -6821,9 +6816,9 @@ tiff_load (struct frame *f, struct image *img) continue; if (count > 1) - img->data.lisp_val = Fcons (Qcount, - Fcons (make_number (count), - img->data.lisp_val)); + img->lisp_data = Fcons (Qcount, + Fcons (make_number (count), + img->lisp_data)); fn_TIFFClose (tiff); if (!rc) @@ -6962,8 +6957,7 @@ static struct image_type gif_type = static void gif_clear_image (struct frame *f, struct image *img) { - /* IMG->data.ptr_val may contain metadata with extension data. */ - img->data.lisp_val = Qnil; + img->lisp_data = Qnil; x_clear_image (f, img); } @@ -7077,22 +7071,19 @@ static const int interlace_increment[] = {8, 8, 4, 2}; static int gif_load (struct frame *f, struct image *img) { - Lisp_Object file, specified_file; - Lisp_Object specified_data; - int rc, width, height, x, y, i; - boolean transparent_p = 0; + Lisp_Object file; + int rc, width, height, x, y, i, j; XImagePtr ximg; ColorMapObject *gif_color_map; unsigned long pixel_colors[256]; GifFileType *gif; - Lisp_Object image; - int ino, image_height, image_width; + int image_height, image_width; gif_memory_source memsrc; - unsigned char *raster; - unsigned int transparency_color_index IF_LINT (= 0); - - specified_file = image_spec_value (img->spec, QCfile, NULL); - specified_data = image_spec_value (img->spec, QCdata, NULL); + Lisp_Object specified_bg = image_spec_value (img->spec, QCbackground, NULL); + Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL); + Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL); + unsigned long bgcolor = 0; + int idx; if (NILP (specified_data)) { @@ -7143,40 +7134,31 @@ gif_load (struct frame *f, struct image *img) /* Read entire contents. */ rc = fn_DGifSlurp (gif); - if (rc == GIF_ERROR) + if (rc == GIF_ERROR || gif->ImageCount <= 0) { image_error ("Error reading `%s'", img->spec, Qnil); fn_DGifCloseFile (gif); return 0; } - image = image_spec_value (img->spec, QCindex, NULL); - ino = INTEGERP (image) ? XFASTINT (image) : 0; - if (ino >= gif->ImageCount) - { - image_error ("Invalid image number `%s' in image `%s'", - image, img->spec); - fn_DGifCloseFile (gif); - return 0; - } - - for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++) - if ((gif->SavedImages[ino].ExtensionBlocks[i].Function - == GIF_LOCAL_DESCRIPTOR_EXTENSION) - && gif->SavedImages[ino].ExtensionBlocks[i].ByteCount == 4 - /* Transparency enabled? */ - && gif->SavedImages[ino].ExtensionBlocks[i].Bytes[0] & 1) + /* Which sub-image are we to display? */ + { + Lisp_Object image_number = image_spec_value (img->spec, QCindex, NULL); + idx = INTEGERP (image_number) ? XFASTINT (image_number) : 0; + if (idx < 0 || idx >= gif->ImageCount) { - transparent_p = 1; - transparency_color_index - = (unsigned char) gif->SavedImages[ino].ExtensionBlocks[i].Bytes[3]; + image_error ("Invalid image number `%s' in image `%s'", + image_number, img->spec); + fn_DGifCloseFile (gif); + return 0; } + } - 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[TOP_CORNER] = gif->SavedImages[idx].ImageDesc.Top; + img->corners[LEFT_CORNER] = gif->SavedImages[idx].ImageDesc.Left; + image_height = gif->SavedImages[idx].ImageDesc.Height; img->corners[BOT_CORNER] = img->corners[TOP_CORNER] + image_height; - image_width = gif->SavedImages[ino].ImageDesc.Width; + image_width = gif->SavedImages[idx].ImageDesc.Width; img->corners[RIGHT_CORNER] = img->corners[LEFT_CORNER] + image_width; width = img->width = max (gif->SWidth, @@ -7200,44 +7182,10 @@ gif_load (struct frame *f, struct image *img) return 0; } - /* Allocate colors. */ - gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap; - if (!gif_color_map) - gif_color_map = gif->SColorMap; - init_color_table (); - memset (pixel_colors, 0, sizeof pixel_colors); - - if (gif_color_map) - for (i = 0; i < gif_color_map->ColorCount; ++i) - { - if (transparent_p && transparency_color_index == i) - { - Lisp_Object specified_bg - = image_spec_value (img->spec, QCbackground, NULL); - pixel_colors[i] = STRINGP (specified_bg) - ? x_alloc_image_color (f, img, specified_bg, - FRAME_BACKGROUND_PIXEL (f)) - : FRAME_BACKGROUND_PIXEL (f); - } - else - { - int r = gif_color_map->Colors[i].Red << 8; - int g = gif_color_map->Colors[i].Green << 8; - int b = gif_color_map->Colors[i].Blue << 8; - pixel_colors[i] = lookup_rgb_color (f, r, g, b); - } - } - -#ifdef COLOR_TABLE_SUPPORT - img->colors = colors_in_color_table (&img->ncolors); - free_color_table (); -#endif /* COLOR_TABLE_SUPPORT */ - - /* Clear the part of the screen image that are not covered by - the image from the GIF file. Full animated GIF support - 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. */ + /* Clear the part of the screen image not covered by the image. + Full animated GIF support requires more 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 < img->corners[TOP_CORNER]; ++y) for (x = 0; x < width; ++x) XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); @@ -7254,67 +7202,146 @@ gif_load (struct frame *f, struct image *img) XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f)); } - /* Read the GIF image into the X image. We use a local variable - `raster' here because RasterBits below is a char *, and invites - problems with bytes >= 0x80. */ - raster = (unsigned char *) gif->SavedImages[ino].RasterBits; - - if (gif->SavedImages[ino].ImageDesc.Interlace) - { - int pass; - int row = interlace_start[0]; + /* Read the GIF image into the X image. */ - pass = 0; + /* FIXME: With the current implementation, loading an animated gif + is quadratic in the number of animation frames, since each frame + is a separate struct image. We must provide a way for a single + gif_load call to construct and save all animation frames. */ - for (y = 0; y < image_height; y++) + init_color_table (); + if (STRINGP (specified_bg)) + bgcolor = x_alloc_image_color (f, img, specified_bg, + FRAME_BACKGROUND_PIXEL (f)); + for (j = 0; j <= idx; ++j) + { + /* We use a local variable `raster' here because RasterBits is a + char *, which invites problems with bytes >= 0x80. */ + struct SavedImage *subimage = gif->SavedImages + j; + unsigned char *raster = (unsigned char *) subimage->RasterBits; + int transparency_color_index = -1; + int disposal = 0; + + /* Find the Graphic Control Extension block for this sub-image. + Extract the disposal method and transparency color. */ + for (i = 0; i < subimage->ExtensionBlockCount; i++) { - if (row >= image_height) - { - row = interlace_start[++pass]; - while (row >= image_height) - row = interlace_start[++pass]; - } + ExtensionBlock *extblock = subimage->ExtensionBlocks + i; - for (x = 0; x < image_width; x++) + if ((extblock->Function == GIF_LOCAL_DESCRIPTOR_EXTENSION) + && extblock->ByteCount == 4 + && extblock->Bytes[0] & 1) { - int c = raster[(y * image_width) + x]; - XPutPixel (ximg, x + img->corners[LEFT_CORNER], - row + img->corners[TOP_CORNER], pixel_colors[c]); + /* From gif89a spec: 1 = "keep in place", 2 = "restore + to background". Treat any other value like 2. */ + disposal = (extblock->Bytes[0] >> 2) & 7; + transparency_color_index = (unsigned char) extblock->Bytes[3]; + break; } - - row += interlace_increment[pass]; } - } - else - { - for (y = 0; y < image_height; ++y) - for (x = 0; x < image_width; ++x) + + /* We can't "keep in place" the first subimage. */ + if (j == 0) + disposal = 2; + + /* Allocate subimage colors. */ + memset (pixel_colors, 0, sizeof pixel_colors); + gif_color_map = subimage->ImageDesc.ColorMap; + if (!gif_color_map) + gif_color_map = gif->SColorMap; + + if (gif_color_map) + for (i = 0; i < gif_color_map->ColorCount; ++i) { - int c = raster[y * image_width + x]; - XPutPixel (ximg, x + img->corners[LEFT_CORNER], - y + img->corners[TOP_CORNER], pixel_colors[c]); + if (transparency_color_index == i) + pixel_colors[i] = STRINGP (specified_bg) + ? bgcolor : FRAME_BACKGROUND_PIXEL (f); + else + { + int r = gif_color_map->Colors[i].Red << 8; + int g = gif_color_map->Colors[i].Green << 8; + int b = gif_color_map->Colors[i].Blue << 8; + pixel_colors[i] = lookup_rgb_color (f, r, g, b); + } } + + /* Apply the pixel values. */ + if (gif->SavedImages[j].ImageDesc.Interlace) + { + int row, pass; + + for (y = 0, row = interlace_start[0], pass = 0; + y < image_height; + y++, row += interlace_increment[pass]) + { + if (row >= image_height) + { + row = interlace_start[++pass]; + while (row >= image_height) + row = interlace_start[++pass]; + } + + for (x = 0; x < image_width; x++) + { + int c = raster[y * image_width + x]; + if (transparency_color_index != c || disposal != 1) + XPutPixel (ximg, x + img->corners[LEFT_CORNER], + row + img->corners[TOP_CORNER], pixel_colors[c]); + } + } + } + else + { + for (y = 0; y < image_height; ++y) + for (x = 0; x < image_width; ++x) + { + int c = raster[y * image_width + x]; + if (transparency_color_index != c || disposal != 1) + XPutPixel (ximg, x + img->corners[LEFT_CORNER], + y + img->corners[TOP_CORNER], pixel_colors[c]); + } + } } +#ifdef COLOR_TABLE_SUPPORT + img->colors = colors_in_color_table (&img->ncolors); + free_color_table (); +#endif /* COLOR_TABLE_SUPPORT */ + /* Save GIF image extension data for `image-metadata'. Format is (count IMAGES extension-data (FUNCTION "BYTES" ...)). */ - img->data.lisp_val = Qnil; - if (gif->SavedImages[ino].ExtensionBlockCount > 0) + img->lisp_data = Qnil; + if (gif->SavedImages[idx].ExtensionBlockCount > 0) { - ExtensionBlock *ext = gif->SavedImages[ino].ExtensionBlocks; - for (i = 0; i < gif->SavedImages[ino].ExtensionBlockCount; i++, ext++) + unsigned int delay = 0; + ExtensionBlock *ext = gif->SavedImages[idx].ExtensionBlocks; + for (i = 0; i < gif->SavedImages[idx].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 = Fcons (Qextension_data, - Fcons (Fnreverse (img->data.lisp_val), - Qnil)); + { + img->lisp_data + = Fcons (make_number (ext->Function), + Fcons (make_unibyte_string (ext->Bytes, ext->ByteCount), + img->lisp_data)); + if (ext->Function == GIF_LOCAL_DESCRIPTOR_EXTENSION + && ext->ByteCount == 4) + { + delay = ext->Bytes[2] << CHAR_BIT; + delay |= ext->Bytes[1]; + } + } + img->lisp_data = Fcons (Qextension_data, + Fcons (img->lisp_data, Qnil)); + if (delay) + img->lisp_data + = Fcons (Qdelay, + Fcons (make_float (((double) delay) * 0.01), + img->lisp_data)); } + if (gif->ImageCount > 1) - img->data.lisp_val = Fcons (Qcount, - Fcons (make_number (gif->ImageCount), - img->data.lisp_val)); + img->lisp_data = Fcons (Qcount, + Fcons (make_number (gif->ImageCount), + img->lisp_data)); fn_DGifCloseFile (gif); @@ -7350,7 +7377,11 @@ gif_load (struct frame *f, struct image *img) ***********************************************************************/ #if defined (HAVE_IMAGEMAGICK) -Lisp_Object Qimagemagick; +static Lisp_Object Qimagemagick; + +static int imagemagick_image_p (Lisp_Object); +static int imagemagick_load (struct frame *, struct image *); +static void imagemagick_clear_image (struct frame *, struct image *); /* Indices of image specification fields in imagemagick_format. */ @@ -7394,6 +7425,18 @@ static struct image_keyword imagemagick_format[IMAGEMAGICK_LAST] = {":crop", IMAGE_DONT_CHECK_VALUE_TYPE, 0} }; +/* Structure describing the image type for any image handled via + ImageMagick. */ + +static struct image_type imagemagick_type = + { + &Qimagemagick, + imagemagick_image_p, + imagemagick_load, + imagemagick_clear_image, + NULL + }; + /* Free X resources of imagemagick image IMG which is used on frame F. */ static void @@ -7425,38 +7468,37 @@ imagemagick_image_p (Lisp_Object object) #define DrawRectangle DrawRectangleGif #include -/* imagemagick_load_image is a helper function for imagemagick_load, - which does the actual loading given contents and size, apart from - frame and image structures, passed from imagemagick_load. +/* ImageMagick 6.5.3 through 6.6.5 hid PixelGetMagickColor for some reason. + Emacs seems to work fine with the hidden version, so unhide it. */ +#include +#if 0x653 <= MagickLibVersion && MagickLibVersion <= 0x665 +extern WandExport void PixelGetMagickColor (const PixelWand *, + MagickPixelPacket *); +#endif + +/* Helper function for imagemagick_load, which does the actual loading + given contents and size, apart from frame and image structures, + passed from imagemagick_load. Uses librimagemagick to do most of + the image processing. - Uses librimagemagick to do most of the image processing. + F is a pointer to the Emacs frame; IMG to the image structure to + prepare; CONTENTS is the string containing the IMAGEMAGICK data to + be parsed; SIZE is the number of bytes of data; and FILENAME is + either the file name or the image data. - Return non-zero if successful. -*/ + Return non-zero if successful. */ static int -imagemagick_load_image (/* Pointer to emacs frame structure. */ - struct frame *f, - /* Pointer to emacs image structure. */ - struct image *img, - /* String containing the IMAGEMAGICK data to - be parsed. */ - unsigned char *contents, - /* Size of data in bytes. */ - unsigned int size, - /* Filename, either pass filename or - contents/size. */ - unsigned char *filename) -{ - unsigned long width; - unsigned long height; - - MagickBooleanType - status; +imagemagick_load_image (struct frame *f, struct image *img, + unsigned char *contents, unsigned int size, + char *filename) +{ + size_t width; + size_t height; + + MagickBooleanType status; XImagePtr ximg; - Lisp_Object specified_bg; - XColor background; int x; int y; @@ -7467,7 +7509,7 @@ imagemagick_load_image (/* Pointer to emacs frame structure. */ MagickPixelPacket pixel; Lisp_Object image; Lisp_Object value; - Lisp_Object crop, geometry; + Lisp_Object crop; long ino; int desired_width, desired_height; double rotation; @@ -7507,15 +7549,15 @@ imagemagick_load_image (/* Pointer to emacs frame structure. */ } if (MagickGetNumberImages(ping_wand) > 1) - img->data.lisp_val = + img->lisp_data = Fcons (Qcount, Fcons (make_number (MagickGetNumberImages (ping_wand)), - img->data.lisp_val)); + img->lisp_data)); DestroyMagickWand (ping_wand); - /* Now, after pinging, we know how many images are inside the - file. If it's not a bundle, the number is one. */ + /* Now we know how many images are inside the file. If it's not a + bundle, the number is one. */ if (filename != NULL) { @@ -7528,23 +7570,18 @@ imagemagick_load_image (/* Pointer to emacs frame structure. */ im_image = ReadImage (image_info, exception); DestroyExceptionInfo (exception); - if (im_image != NULL) - { - image_wand = NewMagickWandFromImage (im_image); - DestroyImage(im_image); - status = MagickTrue; - } - else - status = MagickFalse; + if (im_image == NULL) + goto imagemagick_no_wand; + image_wand = NewMagickWandFromImage (im_image); + DestroyImage(im_image); } else { image_wand = NewMagickWand (); - status = MagickReadImageBlob (image_wand, contents, size); + if (MagickReadImageBlob (image_wand, contents, size) == MagickFalse) + goto imagemagick_error; } - if (status == MagickFalse) goto imagemagick_error; - /* 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 @@ -7585,7 +7622,7 @@ imagemagick_load_image (/* Pointer to emacs frame structure. */ than the alternatives, but it still reads the entire image into memory before croping, which is aparently difficult to avoid when using imagemagick. */ - int w, h, x, y; + int w, h; w = XFASTINT (XCAR (crop)); crop = XCDR (crop); if (CONSP (crop) && INTEGERP (XCAR (crop))) @@ -7628,8 +7665,8 @@ imagemagick_load_image (/* Pointer to emacs frame structure. */ } } - /* Finaly we are done manipulating the image, figure out resulting - width, height, and then transfer ownerwship to Emacs. */ + /* Finally we are done manipulating the image. Figure out the + resulting width/height and transfer ownerwship to Emacs. */ height = MagickGetImageHeight (image_wand); width = MagickGetImageWidth (image_wand); @@ -7699,7 +7736,7 @@ imagemagick_load_image (/* Pointer to emacs frame structure. */ method is also well tested. Some aspects of this method are ad-hoc and needs to be more researched. */ int imagedepth = 24;/*MagickGetImageDepth(image_wand);*/ - char* exportdepth = imagedepth <= 8 ? "I" : "BGRP";/*"RGBP";*/ + const char *exportdepth = imagedepth <= 8 ? "I" : "BGRP";/*"RGBP";*/ /* Try to create a x pixmap to hold the imagemagick pixmap. */ if (!x_create_x_image_and_pixmap (f, width, height, imagedepth, &ximg, &img->pixmap)) @@ -7772,6 +7809,7 @@ imagemagick_load_image (/* Pointer to emacs frame structure. */ imagemagick_error: DestroyMagickWand (image_wand); + imagemagick_no_wand: MagickWandTerminus (); /* TODO more cleanup. */ image_error ("Error parsing IMAGEMAGICK image `%s'", img->spec, Qnil); @@ -7784,8 +7822,7 @@ imagemagick_load_image (/* Pointer to emacs frame structure. */ the prototype thus needs to be compatible with that structure. */ static int -imagemagick_load (struct frame *f, - struct image *img) +imagemagick_load (struct frame *f, struct image *img) { int success_p = 0; Lisp_Object file_name; @@ -7802,7 +7839,7 @@ imagemagick_load (struct frame *f, image_error ("Cannot find image file `%s'", file_name, Qnil); return 0; } - success_p = imagemagick_load_image (f, img, 0, 0, SDATA (file)); + success_p = imagemagick_load_image (f, img, 0, 0, SSDATA (file)); } /* Else its not a file, its a lisp object. Load the image from a lisp object rather than a file. */ @@ -7823,36 +7860,18 @@ imagemagick_load (struct frame *f, return success_p; } -/* Structure describing the image type `imagemagick'. Its the same - type of structure defined for all image formats, handled by Emacs - image functions. See struct image_type in dispextern.h. */ - -static struct image_type imagemagick_type = - { - /* An identifier showing that this is an image structure for the - IMAGEMAGICK format. */ - &Qimagemagick, - /* Handle to a function that can be used to identify a IMAGEMAGICK - file. */ - imagemagick_image_p, - /* Handle to function used to load a IMAGEMAGICK file. */ - imagemagick_load, - /* Handle to function to free resources for IMAGEMAGICK. */ - imagemagick_clear_image, - /* An internal field to link to the next image type in a list of - image types, will be filled in when registering the format. */ - NULL - }; - - DEFUN ("imagemagick-types", Fimagemagick_types, Simagemagick_types, 0, 0, 0, - doc: /* Return the image types supported by ImageMagick. -Note that ImageMagick recognizes many file-types that Emacs does not recognize -as images, such as .c. */) + doc: /* Return a list of image types supported by ImageMagick. +Each entry in this list is a symbol named after an ImageMagick format +tag. See the ImageMagick manual for a list of ImageMagick formats and +their descriptions (http://www.imagemagick.org/script/formats.php). + +Note that ImageMagick recognizes many file-types that Emacs does not +recognize as images, such as C. See `imagemagick-types-inhibit'. */) (void) { Lisp_Object typelist = Qnil; - unsigned long numf; + size_t numf = 0; ExceptionInfo ex; char **imtypes = GetMagickList ("*", &numf, &ex); int i; @@ -7881,11 +7900,11 @@ static int svg_image_p (Lisp_Object object); static int svg_load (struct frame *f, struct image *img); static int svg_load_image (struct frame *, struct image *, - unsigned char *, unsigned int); + unsigned char *, ptrdiff_t); /* The symbol `svg' identifying images of this type. */ -Lisp_Object Qsvg; +static Lisp_Object Qsvg; /* Indices of image specification fields in svg_format, below. */ @@ -7968,7 +7987,6 @@ DEF_IMGLIB_FN (void, rsvg_handle_get_dimensions); DEF_IMGLIB_FN (gboolean, rsvg_handle_write); DEF_IMGLIB_FN (gboolean, rsvg_handle_close); DEF_IMGLIB_FN (GdkPixbuf *, rsvg_handle_get_pixbuf); -DEF_IMGLIB_FN (void, rsvg_handle_free); DEF_IMGLIB_FN (int, gdk_pixbuf_get_width); DEF_IMGLIB_FN (int, gdk_pixbuf_get_height); @@ -8001,7 +8019,6 @@ init_svg_functions (Lisp_Object libraries) LOAD_IMGLIB_FN (library, rsvg_handle_write); LOAD_IMGLIB_FN (library, rsvg_handle_close); LOAD_IMGLIB_FN (library, rsvg_handle_get_pixbuf); - LOAD_IMGLIB_FN (library, rsvg_handle_free); LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_width); LOAD_IMGLIB_FN (gdklib, gdk_pixbuf_get_height); @@ -8027,7 +8044,6 @@ init_svg_functions (Lisp_Object libraries) #define fn_rsvg_handle_write rsvg_handle_write #define fn_rsvg_handle_close rsvg_handle_close #define fn_rsvg_handle_get_pixbuf rsvg_handle_get_pixbuf -#define fn_rsvg_handle_free rsvg_handle_free #define fn_gdk_pixbuf_get_width gdk_pixbuf_get_width #define fn_gdk_pixbuf_get_height gdk_pixbuf_get_height @@ -8059,7 +8075,7 @@ svg_load (struct frame *f, struct image *img) { Lisp_Object file; unsigned char *contents; - int size; + ptrdiff_t size; file = x_find_image_file (file_name); if (!STRINGP (file)) @@ -8069,7 +8085,7 @@ svg_load (struct frame *f, struct image *img) } /* Read the entire file into memory. */ - contents = slurp_file (SDATA (file), &size); + contents = slurp_file (SSDATA (file), &size); if (contents == NULL) { image_error ("Error loading SVG image `%s'", img->spec, Qnil); @@ -8108,11 +8124,11 @@ static int svg_load_image (struct frame *f, /* Pointer to emacs frame structure. */ struct image *img, /* Pointer to emacs image structure. */ unsigned char *contents, /* String containing the SVG XML data to be parsed. */ - unsigned int size) /* Size of data in bytes. */ + ptrdiff_t size) /* Size of data in bytes. */ { RsvgHandle *rsvg_handle; RsvgDimensionData dimension_data; - GError *error = NULL; + GError *err = NULL; GdkPixbuf *pixbuf; int width; int height; @@ -8131,13 +8147,13 @@ svg_load_image (struct frame *f, /* Pointer to emacs frame structure. * rsvg_handle = fn_rsvg_handle_new (); /* Parse the contents argument and fill in the rsvg_handle. */ - fn_rsvg_handle_write (rsvg_handle, contents, size, &error); - if (error) goto rsvg_error; + fn_rsvg_handle_write (rsvg_handle, contents, size, &err); + if (err) goto rsvg_error; /* The parsing is complete, rsvg_handle is ready to used, close it for further writes. */ - fn_rsvg_handle_close (rsvg_handle, &error); - if (error) goto rsvg_error; + fn_rsvg_handle_close (rsvg_handle, &err); + if (err) goto rsvg_error; fn_rsvg_handle_get_dimensions (rsvg_handle, &dimension_data); if (! check_image_size (f, dimension_data.width, dimension_data.height)) @@ -8177,7 +8193,7 @@ svg_load_image (struct frame *f, /* Pointer to emacs frame structure. * color. */ specified_bg = image_spec_value (img->spec, QCbackground, NULL); if (!STRINGP (specified_bg) - || !x_defined_color (f, SDATA (specified_bg), &background, 0)) + || !x_defined_color (f, SSDATA (specified_bg), &background, 0)) { #ifndef HAVE_NS background.pixel = FRAME_BACKGROUND_PIXEL (f); @@ -8252,7 +8268,7 @@ svg_load_image (struct frame *f, /* Pointer to emacs frame structure. * /* FIXME: Use error->message so the user knows what is the actual problem with the image. */ image_error ("Error parsing SVG image `%s'", img->spec, Qnil); - fn_g_error_free (error); + fn_g_error_free (err); return 0; } @@ -8336,8 +8352,6 @@ static struct image_type gs_type = static void gs_clear_image (struct frame *f, struct image *img) { - /* IMG->data.ptr_val may contain a recorded colormap. */ - xfree (img->data.ptr_val); x_clear_image (f, img); } @@ -8446,12 +8460,12 @@ gs_load (struct frame *f, struct image *img) if (NILP (loader)) loader = intern ("gs-load-image"); - img->data.lisp_val = call6 (loader, frame, img->spec, - make_number (img->width), - make_number (img->height), - window_and_pixmap_id, - pixel_colors); - return PROCESSP (img->data.lisp_val); + img->lisp_data = call6 (loader, frame, img->spec, + make_number (img->width), + make_number (img->height), + window_and_pixmap_id, + pixel_colors); + return PROCESSP (img->lisp_data); } @@ -8479,9 +8493,9 @@ x_kill_gs_process (Pixmap pixmap, struct frame *f) /* Kill the GS process. We should have found PIXMAP in the image cache and its image should contain a process object. */ img = c->images[i]; - xassert (PROCESSP (img->data.lisp_val)); - Fkill_process (img->data.lisp_val, Qnil); - img->data.lisp_val = Qnil; + xassert (PROCESSP (img->lisp_data)); + Fkill_process (img->lisp_data, Qnil); + img->lisp_data = Qnil; #if defined (HAVE_X_WINDOWS) @@ -8687,75 +8701,49 @@ as a ratio to the frame height and width. If the value is non-numeric, there is no explicit limit on the size of images. */); Vmax_image_size = make_float (MAX_IMAGE_SIZE); - Qpbm = intern_c_string ("pbm"); - staticpro (&Qpbm); + DEFSYM (Qpbm, "pbm"); ADD_IMAGE_TYPE (Qpbm); - Qxbm = intern_c_string ("xbm"); - staticpro (&Qxbm); + DEFSYM (Qxbm, "xbm"); ADD_IMAGE_TYPE (Qxbm); define_image_type (&xbm_type, 1); define_image_type (&pbm_type, 1); - Qcount = intern_c_string ("count"); - staticpro (&Qcount); - Qextension_data = intern_c_string ("extension-data"); - staticpro (&Qextension_data); - - QCascent = intern_c_string (":ascent"); - staticpro (&QCascent); - QCmargin = intern_c_string (":margin"); - staticpro (&QCmargin); - QCrelief = intern_c_string (":relief"); - staticpro (&QCrelief); - QCconversion = intern_c_string (":conversion"); - staticpro (&QCconversion); - QCcolor_symbols = intern_c_string (":color-symbols"); - staticpro (&QCcolor_symbols); - QCheuristic_mask = intern_c_string (":heuristic-mask"); - staticpro (&QCheuristic_mask); - QCindex = intern_c_string (":index"); - staticpro (&QCindex); - QCgeometry = intern_c_string (":geometry"); - staticpro (&QCgeometry); - QCcrop = intern_c_string (":crop"); - staticpro (&QCcrop); - QCrotation = intern_c_string (":rotation"); - staticpro (&QCrotation); - QCmatrix = intern_c_string (":matrix"); - staticpro (&QCmatrix); - QCcolor_adjustment = intern_c_string (":color-adjustment"); - staticpro (&QCcolor_adjustment); - QCmask = intern_c_string (":mask"); - staticpro (&QCmask); - - Qlaplace = intern_c_string ("laplace"); - staticpro (&Qlaplace); - Qemboss = intern_c_string ("emboss"); - staticpro (&Qemboss); - Qedge_detection = intern_c_string ("edge-detection"); - staticpro (&Qedge_detection); - Qheuristic = intern_c_string ("heuristic"); - staticpro (&Qheuristic); - - Qpostscript = intern_c_string ("postscript"); - staticpro (&Qpostscript); + DEFSYM (Qcount, "count"); + DEFSYM (Qextension_data, "extension-data"); + DEFSYM (Qdelay, "delay"); + + DEFSYM (QCascent, ":ascent"); + DEFSYM (QCmargin, ":margin"); + DEFSYM (QCrelief, ":relief"); + DEFSYM (QCconversion, ":conversion"); + DEFSYM (QCcolor_symbols, ":color-symbols"); + DEFSYM (QCheuristic_mask, ":heuristic-mask"); + DEFSYM (QCindex, ":index"); + DEFSYM (QCgeometry, ":geometry"); + DEFSYM (QCcrop, ":crop"); + DEFSYM (QCrotation, ":rotation"); + DEFSYM (QCmatrix, ":matrix"); + DEFSYM (QCcolor_adjustment, ":color-adjustment"); + DEFSYM (QCmask, ":mask"); + + DEFSYM (Qlaplace, "laplace"); + DEFSYM (Qemboss, "emboss"); + DEFSYM (Qedge_detection, "edge-detection"); + DEFSYM (Qheuristic, "heuristic"); + + DEFSYM (Qpostscript, "postscript"); #ifdef HAVE_GHOSTSCRIPT ADD_IMAGE_TYPE (Qpostscript); - QCloader = intern_c_string (":loader"); - staticpro (&QCloader); - QCbounding_box = intern_c_string (":bounding-box"); - staticpro (&QCbounding_box); - QCpt_width = intern_c_string (":pt-width"); - staticpro (&QCpt_width); - QCpt_height = intern_c_string (":pt-height"); - staticpro (&QCpt_height); + DEFSYM (QCloader, ":loader"); + DEFSYM (QCbounding_box, ":bounding-box"); + DEFSYM (QCpt_width, ":pt-width"); + DEFSYM (QCpt_height, ":pt-height"); #endif /* HAVE_GHOSTSCRIPT */ #ifdef HAVE_NTGUI - Qlibpng_version = intern_c_string ("libpng-version"); - staticpro (&Qlibpng_version); + DEFSYM (Qlibpng_version, "libpng-version"); Fset (Qlibpng_version, #if HAVE_PNG make_number (PNG_LIBPNG_VER) @@ -8766,53 +8754,43 @@ non-numeric, there is no explicit limit on the size of images. */); #endif #if defined (HAVE_XPM) || defined (HAVE_NS) - Qxpm = intern_c_string ("xpm"); - staticpro (&Qxpm); + DEFSYM (Qxpm, "xpm"); ADD_IMAGE_TYPE (Qxpm); #endif #if defined (HAVE_JPEG) || defined (HAVE_NS) - Qjpeg = intern_c_string ("jpeg"); - staticpro (&Qjpeg); + DEFSYM (Qjpeg, "jpeg"); ADD_IMAGE_TYPE (Qjpeg); #endif #if defined (HAVE_TIFF) || defined (HAVE_NS) - Qtiff = intern_c_string ("tiff"); - staticpro (&Qtiff); + DEFSYM (Qtiff, "tiff"); ADD_IMAGE_TYPE (Qtiff); #endif #if defined (HAVE_GIF) || defined (HAVE_NS) - Qgif = intern_c_string ("gif"); - staticpro (&Qgif); + DEFSYM (Qgif, "gif"); ADD_IMAGE_TYPE (Qgif); #endif #if defined (HAVE_PNG) || defined (HAVE_NS) - Qpng = intern_c_string ("png"); - staticpro (&Qpng); + DEFSYM (Qpng, "png"); ADD_IMAGE_TYPE (Qpng); #endif #if defined (HAVE_IMAGEMAGICK) - Qimagemagick = intern_c_string ("imagemagick"); - staticpro (&Qimagemagick); + DEFSYM (Qimagemagick, "imagemagick"); ADD_IMAGE_TYPE (Qimagemagick); #endif #if defined (HAVE_RSVG) - Qsvg = intern_c_string ("svg"); - staticpro (&Qsvg); + DEFSYM (Qsvg, "svg"); ADD_IMAGE_TYPE (Qsvg); #ifdef HAVE_NTGUI /* Other libraries used directly by svg code. */ - Qgdk_pixbuf = intern_c_string ("gdk-pixbuf"); - staticpro (&Qgdk_pixbuf); - Qglib = intern_c_string ("glib"); - staticpro (&Qglib); - Qgobject = intern_c_string ("gobject"); - staticpro (&Qgobject); + DEFSYM (Qgdk_pixbuf, "gdk-pixbuf"); + DEFSYM (Qglib, "glib"); + DEFSYM (Qgobject, "gobject"); #endif /* HAVE_NTGUI */ #endif /* HAVE_RSVG */