/* Functions for image support on window system.
- Copyright (C) 1989, 92, 93, 94, 95, 96, 97, 98, 99, 2000,01,02,03,04
- Free Software Foundation.
+ Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include <config.h>
-#include <signal.h>
#include <stdio.h>
#include <math.h>
+#include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#define COLOR_TABLE_SUPPORT 1
typedef struct x_bitmap_record Bitmap_Record;
-typedef XImage * XImagePtr;
-typedef XImagePtr XImagePtr_or_DC;
#define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
#define NO_PIXMAP None
-#define PNG_BG_COLOR_SHIFT 0
#define RGB_PIXEL_COLOR unsigned long
-#define PIX_MASK_RETAIN(f) 0
-#define PIX_MASK_DRAW(f) 1
+#define PIX_MASK_RETAIN 0
+#define PIX_MASK_DRAW 1
#endif /* HAVE_X_WINDOWS */
#undef COLOR_TABLE_SUPPORT
typedef struct w32_bitmap_record Bitmap_Record;
-typedef XImage *XImagePtr;
-typedef HDC XImagePtr_or_DC;
#define GET_PIXEL(ximg, x, y) GetPixel(ximg, x, y)
#define NO_PIXMAP 0
-#define PNG_BG_COLOR_SHIFT 0
#define RGB_PIXEL_COLOR COLORREF
-#define PIX_MASK_RETAIN(f) 0
-#define PIX_MASK_DRAW(f) 1
+#define PIX_MASK_RETAIN 0
+#define PIX_MASK_DRAW 1
#define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
#define x_defined_color w32_defined_color
#ifdef MAC_OS
#include "macterm.h"
+#include <sys/stat.h>
#ifndef MAC_OSX
#include <alloca.h>
+#include <sys/param.h>
#endif
+#if TARGET_API_MAC_CARBON
#ifdef MAC_OSX
-#include <sys/stat.h>
#include <QuickTime/QuickTime.h>
-#else /* not MAC_OSX */
+#else /* not MAC_OSX */
+#include <QuickTime.h>
+#endif /* not MAC_OSX */
+#else /* not TARGET_API_MAC_CARBON */
#include <Windows.h>
#include <Gestalt.h>
#include <TextUtils.h>
-#endif /* not MAC_OSX */
+#include <ImageCompression.h>
+#include <QuickTimeComponents.h>
+#endif /* not TARGET_API_MAC_CARBON */
/* MAC_TODO : Color tables on Mac. */
#undef COLOR_TABLE_SUPPORT
-/* Mac equivalent of XImage. */
-typedef Pixmap XImagePtr;
#define ZPixmap 0 /* arbitrary */
typedef struct mac_bitmap_record Bitmap_Record;
-typedef XImagePtr XImagePtr_or_DC;
#define GET_PIXEL(ximg, x, y) XGetPixel(ximg, x, y)
#define NO_PIXMAP 0
-#define PNG_BG_COLOR_SHIFT 8
#define RGB_PIXEL_COLOR unsigned long
+/* A black pixel in a mask bitmap/pixmap means ``draw a source
+ pixel''. A white pixel means ``retain the current pixel''. */
+#define PIX_MASK_DRAW RGB_TO_ULONG(0,0,0)
+#define PIX_MASK_RETAIN RGB_TO_ULONG(255,255,255)
+
#define FRAME_X_VISUAL(f) FRAME_X_DISPLAY_INFO (f)->visual
#define x_defined_color mac_defined_color
#define DefaultDepthOfScreen(screen) (one_mac_display_info.n_planes)
int x, y;
unsigned long pixel;
{
- RGBColor color;
+ PixMapHandle pixmap = GetGWorldPixMap (ximage);
+ short depth = GetPixDepth (pixmap);
+
+ if (depth == 32)
+ {
+ char *base_addr = GetPixBaseAddr (pixmap);
+ short row_bytes = GetPixRowBytes (pixmap);
+
+ ((unsigned long *) (base_addr + y * row_bytes))[x] = pixel;
+ }
+ else if (depth == 1)
+ {
+ char *base_addr = GetPixBaseAddr (pixmap);
+ short row_bytes = GetPixRowBytes (pixmap);
+
+ if (pixel == PIX_MASK_DRAW)
+ base_addr[y * row_bytes + x / 8] |= (1 << 7) >> (x & 7);
+ else
+ base_addr[y * row_bytes + x / 8] &= ~((1 << 7) >> (x & 7));
+ }
+ else
+ {
+ CGrafPtr old_port;
+ GDHandle old_gdh;
+ RGBColor color;
+
+ GetGWorld (&old_port, &old_gdh);
+ SetGWorld (ximage, NULL);
+
+ color.red = RED16_FROM_ULONG (pixel);
+ color.green = GREEN16_FROM_ULONG (pixel);
+ color.blue = BLUE16_FROM_ULONG (pixel);
- SetGWorld (ximage, NULL);
+ SetCPixel (x, y, &color);
- color.red = RED16_FROM_ULONG (pixel);
- color.green = GREEN16_FROM_ULONG (pixel);
- color.blue = BLUE16_FROM_ULONG (pixel);
- SetCPixel (x, y, &color);
+ SetGWorld (old_port, old_gdh);
+ }
}
static unsigned long
XImagePtr ximage;
int x, y;
{
- RGBColor color;
+ PixMapHandle pixmap = GetGWorldPixMap (ximage);
+ short depth = GetPixDepth (pixmap);
+
+ if (depth == 32)
+ {
+ char *base_addr = GetPixBaseAddr (pixmap);
+ short row_bytes = GetPixRowBytes (pixmap);
+
+ return ((unsigned long *) (base_addr + y * row_bytes))[x];
+ }
+ else if (depth == 1)
+ {
+ char *base_addr = GetPixBaseAddr (pixmap);
+ short row_bytes = GetPixRowBytes (pixmap);
+
+ if (base_addr[y * row_bytes + x / 8] & (1 << (~x & 7)))
+ return PIX_MASK_DRAW;
+ else
+ return PIX_MASK_RETAIN;
+ }
+ else
+ {
+ CGrafPtr old_port;
+ GDHandle old_gdh;
+ RGBColor color;
+
+ GetGWorld (&old_port, &old_gdh);
+ SetGWorld (ximage, NULL);
- SetGWorld (ximage, NULL);
+ GetCPixel (x, y, &color);
- GetCPixel (x, y, &color);
- return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
+ SetGWorld (old_port, old_gdh);
+ return RGB_TO_ULONG (color.red >> 8, color.green >> 8, color.blue >> 8);
+ }
}
static void
{
UnlockPixels (GetGWorldPixMap (ximg));
}
-#endif
+#endif /* MAC_OS */
/* Functions to access the contents of a bitmap, given an id. */
static struct image_type *image_types;
+/* A list of symbols, one for each supported image type. */
+
+Lisp_Object Vimage_types;
+
+/* An alist of image types and libraries that implement the type. */
+
+Lisp_Object Vimage_library_alist;
+
+/* Cache for delayed-loading image types. */
+
+static Lisp_Object Vimage_type_cache;
+
/* The symbol `xbm' which is used as the type symbol for XBM images. */
Lisp_Object Qxbm;
extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
extern Lisp_Object QCdata, QCtype;
+extern Lisp_Object Qcenter;
Lisp_Object QCascent, QCmargin, QCrelief;
Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
/* Other symbols. */
Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
-Lisp_Object Qcenter;
/* Time in seconds after which images should be removed from the cache
if not displayed. */
/* Function prototypes. */
-static void define_image_type P_ ((struct image_type *type));
+static Lisp_Object define_image_type P_ ((struct image_type *type, int loaded));
static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
static void x_laplace P_ ((struct frame *, struct image *));
static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
Lisp_Object));
+#define CACHE_IMAGE_TYPE(type, status) \
+ do { Vimage_type_cache = Fcons (Fcons (type, status), Vimage_type_cache); } while (0)
+
+#define ADD_IMAGE_TYPE(type) \
+ do { Vimage_types = Fcons (type, Vimage_types); } while (0)
/* Define a new image type from TYPE. This adds a copy of TYPE to
- image_types and adds the symbol *TYPE->type to Vimage_types. */
+ image_types and caches the loading status of TYPE. */
-static void
-define_image_type (type)
+static Lisp_Object
+define_image_type (type, loaded)
struct image_type *type;
+ int loaded;
{
- /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
- The initialized data segment is read-only. */
- struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
- bcopy (type, p, sizeof *p);
- p->next = image_types;
- image_types = p;
- Vimage_types = Fcons (*p->type, Vimage_types);
+ Lisp_Object success;
+
+ if (!loaded)
+ success = Qnil;
+ else
+ {
+ /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
+ The initialized data segment is read-only. */
+ struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
+ bcopy (type, p, sizeof *p);
+ p->next = image_types;
+ image_types = p;
+ success = Qt;
+ }
+
+ CACHE_IMAGE_TYPE (*type->type, success);
+ return success;
}
{
struct image_type *type;
+ /* We must initialize the image-type if it hasn't been already. */
+ if (NILP (Finit_image_library (symbol, Vimage_library_alist)))
+ return 0; /* unimplemented */
+
for (type = image_types; type; type = type->next)
if (EQ (symbol, *type->type))
break;
static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
static void free_image P_ ((struct frame *f, struct image *img));
+static int check_image_size P_ ((struct frame *f, int width, int height));
+#define MAX_IMAGE_SIZE 6.0
+Lisp_Object Vmax_image_size;
/* Allocate and return a new image structure for image specification
SPEC. SPEC has a hash value of HASH. */
}
}
+/* Return 1 if the given widths and heights are valid for display;
+ otherwise, return 0. */
+
+int
+check_image_size (f, width, height)
+ struct frame *f;
+ int width;
+ int height;
+{
+ int w, h;
+
+ if (width <= 0 || height <= 0)
+ return 0;
+
+ if (INTEGERP (Vmax_image_size))
+ w = h = XINT (Vmax_image_size);
+ else if (FLOATP (Vmax_image_size))
+ {
+ if (f != NULL)
+ {
+ w = FRAME_PIXEL_WIDTH (f);
+ h = FRAME_PIXEL_HEIGHT (f);
+ }
+ else
+ w = h = 1024; /* Arbitrary size for unknown frame. */
+ w = (int) (XFLOAT_DATA (Vmax_image_size) * w);
+ h = (int) (XFLOAT_DATA (Vmax_image_size) * h);
+ }
+ else
+ return 1;
+
+ return (width <= w && height <= h);
+}
/* Prepare image IMG for display on frame F. Must be called before
drawing an image. */
drawn in face FACE. */
int
-image_ascent (img, face)
+image_ascent (img, face, slice)
struct image *img;
struct face *face;
+ struct glyph_slice *slice;
{
- int height = img->height + img->vmargin;
+ int height;
int ascent;
+ if (slice->height == img->height)
+ height = img->height + img->vmargin;
+ else if (slice->y == 0)
+ height = slice->height + img->vmargin;
+ else
+ height = slice->height;
+
if (img->ascent == CENTERED_IMAGE_ASCENT)
{
if (face->font)
/* Return the `background' field of IMG. If IMG doesn't have one yet,
it is guessed heuristically. If non-zero, XIMG is an existing
XImage object (or device context with the image selected on W32) to
- use for the heuristic. */
+ use for the heuristic. */
RGB_PIXEL_COLOR
image_background (img, f, ximg)
if (free_ximg)
Destroy_Image (ximg, prev);
-
+
img->background_valid = 1;
}
}
img->background_transparent
- = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN (f));
+ = (four_corners_best (mask, img->width, img->height) == PIX_MASK_RETAIN);
if (free_mask)
Destroy_Image (mask, prev);
if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
break;
+ if (img && img->load_failed_p)
+ {
+ free_image (f, img);
+ img = NULL;
+ }
+
/* If not found, create a new image and cache it. */
if (img == NULL)
{
#ifdef HAVE_NTGUI
/* Macro for defining functions that will be loaded from image DLLs. */
-#define DEF_IMGLIB_FN(func) FARPROC fn_##func
+#define DEF_IMGLIB_FN(func) int (FAR CDECL *fn_##func)()
/* Macro for loading those image functions from the library. */
#define LOAD_IMGLIB_FN(lib,func) { \
if (!fn_##func) return 0; \
}
+/* Load a DLL implementing an image type.
+ The `image-library-alist' variable associates a symbol,
+ identifying an image type, to a list of possible filenames.
+ The function returns NULL if no library could be loaded for
+ the given image type, or if the library was previously loaded;
+ else the handle of the DLL. */
+static HMODULE
+w32_delayed_load (Lisp_Object libraries, Lisp_Object type)
+{
+ HMODULE library = NULL;
+
+ if (CONSP (libraries) && NILP (Fassq (type, Vimage_type_cache)))
+ {
+ Lisp_Object dlls = Fassq (type, libraries);
+
+ if (CONSP (dlls))
+ for (dlls = XCDR (dlls); CONSP (dlls); dlls = XCDR (dlls))
+ {
+ CHECK_STRING_CAR (dlls);
+ if (library = LoadLibrary (SDATA (XCAR (dlls))))
+ break;
+ }
+ }
+
+ return library;
+}
+
#endif /* HAVE_NTGUI */
static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
and store its handle in *pixmap. */
*pixmap = CreateDIBSection (hdc, &((*ximg)->info),
(depth < 16) ? DIB_PAL_COLORS : DIB_RGB_COLORS,
- &((*ximg)->data), NULL, 0);
+ /* casting avoids a GCC warning */
+ (void **)&((*ximg)->data), NULL, 0);
/* Realize display palette and garbage all frames. */
release_frame_dc (f, hdc);
*pixmap = XCreatePixmap (display, window, width, height, depth);
if (*pixmap == NO_PIXMAP)
{
- x_destroy_x_image (*ximg);
*ximg = NULL;
image_error ("Unable to create X pixmap", Qnil, Qnil);
return 0;
File Handling
***********************************************************************/
-static Lisp_Object x_find_image_file P_ ((Lisp_Object));
static unsigned char *slurp_file P_ ((char *, int *));
x-bitmap-file-path. Value is the full name of the file found, or
nil if not found. */
-static Lisp_Object
+Lisp_Object
x_find_image_file (file)
Lisp_Object file;
{
if (stat (file, &st) == 0
&& (fp = fopen (file, "rb")) != NULL
- && (buf = (char *) xmalloc (st.st_size),
+ && (buf = (unsigned char *) xmalloc (st.st_size),
fread (buf, 1, st.st_size, fp) == st.st_size))
{
*size = st.st_size;
Lisp_Object specified_file, *file;
FSSpec *fss;
{
-#if TARGET_API_MAC_CARBON
+#if MAC_OSX
FSRef fsr;
-#else
- Str255 mac_pathname;
#endif
OSErr err;
return fnfErr; /* file or directory not found;
incomplete pathname */
/* Try to open the image file. */
-#if TARGET_API_MAC_CARBON
+#if MAC_OSX
err = FSPathMakeRef (SDATA (*file), &fsr, NULL);
if (err == noErr)
err = FSGetCatalogInfo (&fsr, kFSCatInfoNone, NULL, NULL, fss, NULL);
#else
- if (posix_to_mac_pathname (SDATA (*file), mac_pathname, MAXPATHLEN+1) == 0)
- return fnfErr;
- c2pstr (mac_pathname);
- err = FSMakeFSSpec (0, 0, mac_pathname, fss);
+ err = posix_pathname_to_fsspec (SDATA (*file), fss);
#endif
return err;
}
GraphicsImportComponent gi;
Rect rect;
int width, height;
+ ImageDescriptionHandle desc_handle;
short draw_all_pixels;
Lisp_Object specified_bg;
XColor color;
goto error;
}
}
- err = GraphicsImportGetNaturalBounds (gi, &rect);
- if (err != noErr)
+ err = GraphicsImportGetImageDescription (gi, &desc_handle);
+ if (err != noErr || desc_handle == NULL)
{
image_error ("Error reading `%s'", img->spec, Qnil);
goto error;
}
- width = img->width = rect.right - rect.left;
- height = img->height = rect.bottom - rect.top;
+ width = img->width = (*desc_handle)->width;
+ height = img->height = (*desc_handle)->height;
+ DisposeHandle ((Handle)desc_handle);
+
+ if (!check_image_size (f, width, height))
+ {
+ image_error ("Invalid image size", Qnil, Qnil);
+ goto error;
+ }
+
err = GraphicsImportDoesDrawAllPixels (gi, &draw_all_pixels);
#if 0
/* Don't check the error code here. It may have an undocumented
goto error;
if (draw_all_pixels != graphicsImporterDrawsAllPixels)
{
+ CGrafPtr old_port;
+ GDHandle old_gdh;
+
+ GetGWorld (&old_port, &old_gdh);
SetGWorld (ximg, NULL);
bg_color.red = color.red;
bg_color.green = color.green;
#else
EraseRect (&(ximg->portRect));
#endif
+ SetGWorld (old_port, old_gdh);
}
GraphicsImportSetGWorld (gi, ximg, NULL);
GraphicsImportDraw (gi);
UNGCPRO;
return 0;
}
- path = CFStringCreateWithCString (NULL, SDATA (file),
- kCFStringEncodingUTF8);
+ path = cfstring_create_with_string (file);
url = CFURLCreateWithFileSystemPath (NULL, path,
kCFURLPOSIXPathStyle, 0);
CFRelease (path);
image_error ("Error reading image `%s'", img->spec, Qnil);
return 0;
}
+ width = img->width = CGImageGetWidth (image);
+ height = img->height = CGImageGetHeight (image);
+
+ if (!check_image_size (f, width, height))
+ {
+ UNGCPRO;
+ image_error ("Invalid image size", Qnil, Qnil);
+ return 0;
+ }
if (png_p)
{
color.blue = BLUE16_FROM_ULONG (color.pixel);
}
}
- width = img->width = CGImageGetWidth (image);
- height = img->height = CGImageGetHeight (image);
+
if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
{
CGImageRelease (image);
static int xbm_load_image P_ ((struct frame *f, struct image *img,
unsigned char *, unsigned char *));
static int xbm_image_p P_ ((Lisp_Object object));
-static int xbm_read_bitmap_data P_ ((unsigned char *, unsigned char *,
+static int xbm_read_bitmap_data P_ ((struct frame *f,
+ unsigned char *, unsigned char *,
int *, int *, unsigned char **));
static int xbm_file_p P_ ((Lisp_Object));
CONTENTS looks like an in-memory XBM file. */
static int
-xbm_read_bitmap_data (contents, end, width, height, data)
+xbm_read_bitmap_data (f, contents, end, width, height, data)
+ struct frame *f;
unsigned char *contents, *end;
int *width, *height;
unsigned char **data;
expect (XBM_TK_NUMBER);
}
- if (*width < 0 || *height < 0)
+ if (!check_image_size (f, *width, *height))
goto failure;
else if (data == NULL)
goto success;
bytes_per_line = (*width + 7) / 8 + padding_p;
nbytes = bytes_per_line * *height;
- p = *data = (char *) xmalloc (nbytes);
+ p = *data = (unsigned char *) xmalloc (nbytes);
if (v10)
{
unsigned char *data;
int success_p = 0;
- rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
+ rc = xbm_read_bitmap_data (f, contents, end, &img->width, &img->height, &data);
if (rc)
{
unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
non_default_colors = 1;
}
- Create_Pixmap_From_Bitmap_Data (f, img, data,
+ Create_Pixmap_From_Bitmap_Data (f, img, data,
foreground, background,
non_default_colors);
xfree (data);
{
int w, h;
return (STRINGP (data)
- && xbm_read_bitmap_data (SDATA (data),
+ && xbm_read_bitmap_data (NULL, SDATA (data),
(SDATA (data)
+ SBYTES (data)),
&w, &h, NULL));
XPM images
***********************************************************************/
-#ifdef HAVE_XPM
+#if defined (HAVE_XPM) || defined (MAC_OS)
static int xpm_image_p P_ ((Lisp_Object object));
static int xpm_load P_ ((struct frame *f, struct image *img));
static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
+#endif /* HAVE_XPM || MAC_OS */
+
+#ifdef HAVE_XPM
#ifdef HAVE_NTGUI
/* Indicate to xpm.h that we don't have Xlib. */
#define FOR_MSW
/* simx.h in xpm defines XColor and XImage differently than Emacs. */
+/* It also defines Display the same way as Emacs, but gcc 3.3 still barfs. */
#define XColor xpm_XColor
#define XImage xpm_XImage
+#define Display xpm_Display
#define PIXEL_ALREADY_TYPEDEFED
#include "X11/xpm.h"
#undef FOR_MSW
#undef XColor
#undef XImage
+#undef Display
#undef PIXEL_ALREADY_TYPEDEFED
#else
#include "X11/xpm.h"
#endif /* HAVE_NTGUI */
+#endif /* HAVE_XPM */
+#if defined (HAVE_XPM) || defined (MAC_OS)
/* The symbol `xpm' identifying XPM-format images. */
Lisp_Object Qxpm;
DEF_IMGLIB_FN (XpmReadFileToImage);
DEF_IMGLIB_FN (XImageFree);
-
static int
-init_xpm_functions (void)
+init_xpm_functions (Lisp_Object libraries)
{
HMODULE library;
- if (!(library = LoadLibrary ("libXpm.dll")))
+ if (!(library = w32_delayed_load (libraries, Qxpm)))
return 0;
LOAD_IMGLIB_FN (library, XpmFreeAttributes);
|| xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
}
+#endif /* HAVE_XPM || MAC_OS */
/* Load image IMG which will be displayed on frame F. Value is
non-zero if successful. */
+#ifdef HAVE_XPM
+
static int
xpm_load (f, img)
struct frame *f;
#endif /* HAVE_XPM */
-\f
-/***********************************************************************
- Color table
- ***********************************************************************/
+#ifdef MAC_OS
-#ifdef COLOR_TABLE_SUPPORT
+/* XPM support functions for Mac OS where libxpm is not available.
+ Only XPM version 3 (without any extensions) is supported. */
+
+static int xpm_scan P_ ((unsigned char **, unsigned char *,
+ unsigned char **, int *));
+static Lisp_Object xpm_make_color_table_v
+ P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
+ Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
+static void xpm_put_color_table_v P_ ((Lisp_Object, unsigned char *,
+ int, Lisp_Object));
+static Lisp_Object xpm_get_color_table_v P_ ((Lisp_Object,
+ unsigned char *, int));
+static Lisp_Object xpm_make_color_table_h
+ P_ ((void (**) (Lisp_Object, unsigned char *, int, Lisp_Object),
+ Lisp_Object (**) (Lisp_Object, unsigned char *, int)));
+static void xpm_put_color_table_h P_ ((Lisp_Object, unsigned char *,
+ int, Lisp_Object));
+static Lisp_Object xpm_get_color_table_h P_ ((Lisp_Object,
+ unsigned char *, int));
+static int xpm_str_to_color_key P_ ((char *));
+static int xpm_load_image P_ ((struct frame *, struct image *,
+ unsigned char *, unsigned char *));
-/* An entry in the color table mapping an RGB color to a pixel color. */
+/* Tokens returned from xpm_scan. */
-struct ct_color
+enum xpm_token
{
- int r, g, b;
- unsigned long pixel;
-
- /* Next in color table collision list. */
- struct ct_color *next;
+ XPM_TK_IDENT = 256,
+ XPM_TK_STRING,
+ XPM_TK_EOF
};
-/* The bucket vector size to use. Must be prime. */
-
-#define CT_SIZE 101
-
-/* Value is a hash of the RGB color given by R, G, and B. */
+/* Scan an XPM data and return a character (< 256) or a token defined
+ by enum xpm_token above. *S and END are the start (inclusive) and
+ the end (exclusive) addresses of the data, respectively. Advance
+ *S while scanning. If token is either XPM_TK_IDENT or
+ XPM_TK_STRING, *BEG and *LEN are set to the start address and the
+ length of the corresponding token, respectively. */
-#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
+static int
+xpm_scan (s, end, beg, len)
+ unsigned char **s, *end, **beg;
+ int *len;
+{
+ int c;
-/* The color hash table. */
+ while (*s < end)
+ {
+ /* Skip white-space. */
+ while (*s < end && (c = *(*s)++, isspace (c)))
+ ;
-struct ct_color **ct_table;
+ /* gnus-pointer.xpm uses '-' in its identifier.
+ sb-dir-plus.xpm uses '+' in its identifier. */
+ if (isalpha (c) || c == '_' || c == '-' || c == '+')
+ {
+ *beg = *s - 1;
+ while (*s < end &&
+ (c = **s, isalnum (c) || c == '_' || c == '-' || c == '+'))
+ ++*s;
+ *len = *s - *beg;
+ return XPM_TK_IDENT;
+ }
+ else if (c == '"')
+ {
+ *beg = *s;
+ while (*s < end && **s != '"')
+ ++*s;
+ *len = *s - *beg;
+ if (*s < end)
+ ++*s;
+ return XPM_TK_STRING;
+ }
+ else if (c == '/')
+ {
+ if (*s < end && **s == '*')
+ {
+ /* C-style comment. */
+ ++*s;
+ do
+ {
+ while (*s < end && *(*s)++ != '*')
+ ;
+ }
+ while (*s < end && **s != '/');
+ if (*s < end)
+ ++*s;
+ }
+ else
+ return c;
+ }
+ else
+ return c;
+ }
-/* Number of entries in the color table. */
+ return XPM_TK_EOF;
+}
-int ct_colors_allocated;
+/* Functions for color table lookup in XPM data. A Key is a string
+ specifying the color of each pixel in XPM data. A value is either
+ an integer that specifies a pixel color, Qt that specifies
+ transparency, or Qnil for the unspecified color. If the length of
+ the key string is one, a vector is used as a table. Otherwise, a
+ hash table is used. */
-/* Initialize the color table. */
+static Lisp_Object
+xpm_make_color_table_v (put_func, get_func)
+ void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
+ Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
+{
+ *put_func = xpm_put_color_table_v;
+ *get_func = xpm_get_color_table_v;
+ return Fmake_vector (make_number (256), Qnil);
+}
static void
-init_color_table ()
+xpm_put_color_table_v (color_table, chars_start, chars_len, color)
+ Lisp_Object color_table;
+ unsigned char *chars_start;
+ int chars_len;
+ Lisp_Object color;
{
- int size = CT_SIZE * sizeof (*ct_table);
- ct_table = (struct ct_color **) xmalloc (size);
- bzero (ct_table, size);
- ct_colors_allocated = 0;
+ XVECTOR (color_table)->contents[*chars_start] = color;
}
+static Lisp_Object
+xpm_get_color_table_v (color_table, chars_start, chars_len)
+ Lisp_Object color_table;
+ unsigned char *chars_start;
+ int chars_len;
+{
+ return XVECTOR (color_table)->contents[*chars_start];
+}
-/* Free memory associated with the color table. */
+static Lisp_Object
+xpm_make_color_table_h (put_func, get_func)
+ void (**put_func) (Lisp_Object, unsigned char *, int, Lisp_Object);
+ Lisp_Object (**get_func) (Lisp_Object, unsigned char *, int);
+{
+ *put_func = xpm_put_color_table_h;
+ *get_func = xpm_get_color_table_h;
+ return make_hash_table (Qequal, make_number (DEFAULT_HASH_SIZE),
+ make_float (DEFAULT_REHASH_SIZE),
+ make_float (DEFAULT_REHASH_THRESHOLD),
+ Qnil, Qnil, Qnil);
+}
static void
-free_color_table ()
+xpm_put_color_table_h (color_table, chars_start, chars_len, color)
+ Lisp_Object color_table;
+ unsigned char *chars_start;
+ int chars_len;
+ Lisp_Object color;
{
- int i;
- struct ct_color *p, *next;
+ struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
+ unsigned hash_code;
+ Lisp_Object chars = make_unibyte_string (chars_start, chars_len);
- for (i = 0; i < CT_SIZE; ++i)
- for (p = ct_table[i]; p; p = next)
- {
- next = p->next;
- xfree (p);
- }
+ hash_lookup (table, chars, &hash_code);
+ hash_put (table, chars, color, hash_code);
+}
- xfree (ct_table);
- ct_table = NULL;
+static Lisp_Object
+xpm_get_color_table_h (color_table, chars_start, chars_len)
+ Lisp_Object color_table;
+ unsigned char *chars_start;
+ int chars_len;
+{
+ struct Lisp_Hash_Table *table = XHASH_TABLE (color_table);
+ int i = hash_lookup (table, make_unibyte_string (chars_start, chars_len),
+ NULL);
+
+ return i >= 0 ? HASH_VALUE (table, i) : Qnil;
}
+enum xpm_color_key {
+ XPM_COLOR_KEY_S,
+ XPM_COLOR_KEY_M,
+ XPM_COLOR_KEY_G4,
+ XPM_COLOR_KEY_G,
+ XPM_COLOR_KEY_C
+};
-/* Value is a pixel color for RGB color R, G, B on frame F. If an
- entry for that color already is in the color table, return the
- pixel color of that entry. Otherwise, allocate a new color for R,
- G, B, and make an entry in the color table. */
+static char xpm_color_key_strings[][4] = {"s", "m", "g4", "g", "c"};
-static unsigned long
-lookup_rgb_color (f, r, g, b)
+static int
+xpm_str_to_color_key (s)
+ char *s;
+{
+ int i;
+
+ for (i = 0;
+ i < sizeof xpm_color_key_strings / sizeof xpm_color_key_strings[0];
+ i++)
+ if (strcmp (xpm_color_key_strings[i], s) == 0)
+ return i;
+ return -1;
+}
+
+static int
+xpm_load_image (f, img, contents, end)
struct frame *f;
- int r, g, b;
+ struct image *img;
+ unsigned char *contents, *end;
{
- unsigned hash = CT_HASH_RGB (r, g, b);
- int i = hash % CT_SIZE;
- struct ct_color *p;
- Display_Info *dpyinfo;
+ unsigned char *s = contents, *beg, *str;
+ unsigned char buffer[BUFSIZ];
+ int width, height, x, y;
+ int num_colors, chars_per_pixel;
+ int len, LA1;
+ void (*put_color_table) (Lisp_Object, unsigned char *, int, Lisp_Object);
+ Lisp_Object (*get_color_table) (Lisp_Object, unsigned char *, int);
+ Lisp_Object frame, color_symbols, color_table;
+ int best_key, have_mask = 0;
+ XImagePtr ximg = NULL, mask_img = NULL;
- /* Handle TrueColor visuals specially, which improves performance by
- two orders of magnitude. Freeing colors on TrueColor visuals is
- a nop, and pixel colors specify RGB values directly. See also
- the Xlib spec, chapter 3.1. */
- dpyinfo = FRAME_X_DISPLAY_INFO (f);
- if (dpyinfo->red_bits > 0)
- {
- unsigned long pr, pg, pb;
+#define match() \
+ LA1 = xpm_scan (&s, end, &beg, &len)
- /* Apply gamma-correction like normal color allocation does. */
- if (f->gamma)
- {
- XColor color;
- color.red = r, color.green = g, color.blue = b;
- gamma_correct (f, &color);
- r = color.red, g = color.green, b = color.blue;
- }
+#define expect(TOKEN) \
+ if (LA1 != (TOKEN)) \
+ goto failure; \
+ else \
+ match ()
- /* Scale down RGB values to the visual's bits per RGB, and shift
- them to the right position in the pixel color. Note that the
- original RGB values are 16-bit values, as usual in X. */
- pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset;
- pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
- pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset;
+#define expect_ident(IDENT) \
+ if (LA1 == XPM_TK_IDENT \
+ && strlen ((IDENT)) == len && memcmp ((IDENT), beg, len) == 0) \
+ match (); \
+ else \
+ goto failure
- /* Assemble the pixel color. */
- return pr | pg | pb;
- }
-
- for (p = ct_table[i]; p; p = p->next)
- if (p->r == r && p->g == g && p->b == b)
- break;
+ if (!(end - s >= 9 && memcmp (s, "/* XPM */", 9) == 0))
+ goto failure;
+ s += 9;
+ match();
+ expect_ident ("static");
+ expect_ident ("char");
+ expect ('*');
+ expect (XPM_TK_IDENT);
+ expect ('[');
+ expect (']');
+ expect ('=');
+ expect ('{');
+ expect (XPM_TK_STRING);
+ if (len >= BUFSIZ)
+ goto failure;
+ memcpy (buffer, beg, len);
+ buffer[len] = '\0';
+ if (sscanf (buffer, "%d %d %d %d", &width, &height,
+ &num_colors, &chars_per_pixel) != 4
+ || width <= 0 || height <= 0
+ || num_colors <= 0 || chars_per_pixel <= 0)
+ goto failure;
- if (p == NULL)
+ if (!check_image_size (f, width, height))
{
+ image_error ("Invalid image size", Qnil, Qnil);
+ goto failure;
+ }
-#ifdef HAVE_X_WINDOWS
+ expect (',');
+
+ XSETFRAME (frame, f);
+ if (!NILP (Fxw_display_color_p (frame)))
+ best_key = XPM_COLOR_KEY_C;
+ else if (!NILP (Fx_display_grayscale_p (frame)))
+ best_key = (XFASTINT (Fx_display_planes (frame)) > 2
+ ? XPM_COLOR_KEY_G : XPM_COLOR_KEY_G4);
+ else
+ best_key = XPM_COLOR_KEY_M;
+
+ color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
+ if (chars_per_pixel == 1)
+ color_table = xpm_make_color_table_v (&put_color_table,
+ &get_color_table);
+ else
+ color_table = xpm_make_color_table_h (&put_color_table,
+ &get_color_table);
+
+ while (num_colors-- > 0)
+ {
+ unsigned char *color, *max_color;
+ int key, next_key, max_key = 0;
+ Lisp_Object symbol_color = Qnil, color_val;
+ XColor cdef;
+
+ expect (XPM_TK_STRING);
+ if (len <= chars_per_pixel || len >= BUFSIZ + chars_per_pixel)
+ goto failure;
+ memcpy (buffer, beg + chars_per_pixel, len - chars_per_pixel);
+ buffer[len - chars_per_pixel] = '\0';
+
+ str = strtok (buffer, " \t");
+ if (str == NULL)
+ goto failure;
+ key = xpm_str_to_color_key (str);
+ if (key < 0)
+ goto failure;
+ do
+ {
+ color = strtok (NULL, " \t");
+ if (color == NULL)
+ goto failure;
+
+ while (str = strtok (NULL, " \t"))
+ {
+ next_key = xpm_str_to_color_key (str);
+ if (next_key >= 0)
+ break;
+ color[strlen (color)] = ' ';
+ }
+
+ if (key == XPM_COLOR_KEY_S)
+ {
+ if (NILP (symbol_color))
+ symbol_color = build_string (color);
+ }
+ else if (max_key < key && key <= best_key)
+ {
+ max_key = key;
+ max_color = color;
+ }
+ key = next_key;
+ }
+ while (str);
+
+ color_val = Qnil;
+ if (!NILP (color_symbols) && !NILP (symbol_color))
+ {
+ Lisp_Object specified_color = Fassoc (symbol_color, color_symbols);
+
+ if (CONSP (specified_color) && STRINGP (XCDR (specified_color)))
+ if (xstricmp (SDATA (XCDR (specified_color)), "None") == 0)
+ color_val = Qt;
+ else if (x_defined_color (f, SDATA (XCDR (specified_color)),
+ &cdef, 0))
+ color_val = make_number (cdef.pixel);
+ }
+ if (NILP (color_val) && max_key > 0)
+ if (xstricmp (max_color, "None") == 0)
+ color_val = Qt;
+ else if (x_defined_color (f, max_color, &cdef, 0))
+ color_val = make_number (cdef.pixel);
+ if (!NILP (color_val))
+ (*put_color_table) (color_table, beg, chars_per_pixel, color_val);
+
+ expect (',');
+ }
+
+ if (!x_create_x_image_and_pixmap (f, width, height, 0,
+ &ximg, &img->pixmap)
+ || !x_create_x_image_and_pixmap (f, width, height, 1,
+ &mask_img, &img->mask))
+ {
+ image_error ("Out of memory (%s)", img->spec, Qnil);
+ goto error;
+ }
+
+ for (y = 0; y < height; y++)
+ {
+ expect (XPM_TK_STRING);
+ str = beg;
+ if (len < width * chars_per_pixel)
+ goto failure;
+ for (x = 0; x < width; x++, str += chars_per_pixel)
+ {
+ Lisp_Object color_val =
+ (*get_color_table) (color_table, str, chars_per_pixel);
+
+ XPutPixel (ximg, x, y,
+ (INTEGERP (color_val) ? XINT (color_val)
+ : FRAME_FOREGROUND_PIXEL (f)));
+ XPutPixel (mask_img, x, y,
+ (!EQ (color_val, Qt) ? PIX_MASK_DRAW
+ : (have_mask = 1, PIX_MASK_RETAIN)));
+ }
+ if (y + 1 < height)
+ expect (',');
+ }
+
+ img->width = width;
+ img->height = height;
+
+ x_put_x_image (f, ximg, img->pixmap, width, height);
+ x_destroy_x_image (ximg);
+ if (have_mask)
+ {
+ /* Fill in the background_transparent field while we have the
+ mask handy. */
+ image_background_transparent (img, f, mask_img);
+
+ x_put_x_image (f, mask_img, img->mask, width, height);
+ x_destroy_x_image (mask_img);
+ }
+ else
+ {
+ x_destroy_x_image (mask_img);
+ Free_Pixmap (FRAME_X_DISPLAY (f), img->mask);
+ img->mask = NO_PIXMAP;
+ }
+
+ return 1;
+
+ failure:
+ image_error ("Invalid XPM file (%s)", img->spec, Qnil);
+ error:
+ x_destroy_x_image (ximg);
+ x_destroy_x_image (mask_img);
+ x_clear_image (f, img);
+ return 0;
+
+#undef match
+#undef expect
+#undef expect_ident
+}
+
+static int
+xpm_load (f, img)
+ struct frame *f;
+ struct image *img;
+{
+ int success_p = 0;
+ Lisp_Object file_name;
+
+ /* If IMG->spec specifies a file name, create a non-file spec from it. */
+ file_name = image_spec_value (img->spec, QCfile, NULL);
+ if (STRINGP (file_name))
+ {
+ Lisp_Object file;
+ unsigned char *contents;
+ int size;
+ struct gcpro gcpro1;
+
+ file = x_find_image_file (file_name);
+ GCPRO1 (file);
+ if (!STRINGP (file))
+ {
+ image_error ("Cannot find image file `%s'", file_name, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ contents = slurp_file (SDATA (file), &size);
+ if (contents == NULL)
+ {
+ image_error ("Error loading XPM image `%s'", img->spec, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
+ success_p = xpm_load_image (f, img, contents, contents + size);
+ xfree (contents);
+ UNGCPRO;
+ }
+ else
+ {
+ Lisp_Object data;
+
+ data = image_spec_value (img->spec, QCdata, NULL);
+ success_p = xpm_load_image (f, img, SDATA (data),
+ SDATA (data) + SBYTES (data));
+ }
+
+ return success_p;
+}
+
+#endif /* MAC_OS */
+
+
+\f
+/***********************************************************************
+ Color table
+ ***********************************************************************/
+
+#ifdef COLOR_TABLE_SUPPORT
+
+/* An entry in the color table mapping an RGB color to a pixel color. */
+
+struct ct_color
+{
+ int r, g, b;
+ unsigned long pixel;
+
+ /* Next in color table collision list. */
+ struct ct_color *next;
+};
+
+/* The bucket vector size to use. Must be prime. */
+
+#define CT_SIZE 101
+
+/* Value is a hash of the RGB color given by R, G, and B. */
+
+#define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
+
+/* The color hash table. */
+
+struct ct_color **ct_table;
+
+/* Number of entries in the color table. */
+
+int ct_colors_allocated;
+
+/* Initialize the color table. */
+
+static void
+init_color_table ()
+{
+ int size = CT_SIZE * sizeof (*ct_table);
+ ct_table = (struct ct_color **) xmalloc (size);
+ bzero (ct_table, size);
+ ct_colors_allocated = 0;
+}
+
+
+/* Free memory associated with the color table. */
+
+static void
+free_color_table ()
+{
+ int i;
+ struct ct_color *p, *next;
+
+ for (i = 0; i < CT_SIZE; ++i)
+ for (p = ct_table[i]; p; p = next)
+ {
+ next = p->next;
+ xfree (p);
+ }
+
+ xfree (ct_table);
+ ct_table = NULL;
+}
+
+
+/* Value is a pixel color for RGB color R, G, B on frame F. If an
+ entry for that color already is in the color table, return the
+ pixel color of that entry. Otherwise, allocate a new color for R,
+ G, B, and make an entry in the color table. */
+
+static unsigned long
+lookup_rgb_color (f, r, g, b)
+ struct frame *f;
+ int r, g, b;
+{
+ unsigned hash = CT_HASH_RGB (r, g, b);
+ int i = hash % CT_SIZE;
+ struct ct_color *p;
+ Display_Info *dpyinfo;
+
+ /* Handle TrueColor visuals specially, which improves performance by
+ two orders of magnitude. Freeing colors on TrueColor visuals is
+ a nop, and pixel colors specify RGB values directly. See also
+ the Xlib spec, chapter 3.1. */
+ dpyinfo = FRAME_X_DISPLAY_INFO (f);
+ if (dpyinfo->red_bits > 0)
+ {
+ unsigned long pr, pg, pb;
+
+ /* Apply gamma-correction like normal color allocation does. */
+ if (f->gamma)
+ {
+ XColor color;
+ color.red = r, color.green = g, color.blue = b;
+ gamma_correct (f, &color);
+ r = color.red, g = color.green, b = color.blue;
+ }
+
+ /* Scale down RGB values to the visual's bits per RGB, and shift
+ them to the right position in the pixel color. Note that the
+ original RGB values are 16-bit values, as usual in X. */
+ pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset;
+ pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset;
+ pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset;
+
+ /* Assemble the pixel color. */
+ return pr | pg | pb;
+ }
+
+ for (p = ct_table[i]; p; p = p->next)
+ if (p->r == r && p->g == g && p->b == b)
+ break;
+
+ if (p == NULL)
+ {
+
+#ifdef HAVE_X_WINDOWS
XColor color;
Colormap cmap;
int rc;
#ifdef MAC_OS
#define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, NULL, 0, NULL)
-#define MaskForeground(f) PIX_MASK_DRAW (f)
+#define MaskForeground(f) PIX_MASK_DRAW
#else
#define XCreateGC_pixmap(dpy, pixmap) XCreateGC (dpy, pixmap, 0, NULL)
#define MaskForeground(f) WHITE_PIX_DEFAULT (f)
for (y = 0; y < img->height; ++y)
for (x = 0; x < img->width; ++x)
XPutPixel (mask_img, x, y, (XGetPixel (ximg, x, y) != bg
- ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f)));
+ ? PIX_MASK_DRAW : PIX_MASK_RETAIN));
/* Fill in the background_transparent field while we have the mask handy. */
image_background_transparent (img, f, mask_img);
max_color_idx = 255;
}
- if (width < 0
- || height < 0
+ if (!check_image_size (f, width, height)
|| (type != PBM_MONO && max_color_idx < 0))
goto error;
/* Maybe fill in the background field while we have ximg handy. */
if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
- IMAGE_BACKGROUND (img, f, ximg);
+ /* Casting avoids a GCC warning. */
+ IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
/* Put the image into a pixmap. */
x_put_x_image (f, ximg, img->pixmap, width, height);
x_destroy_x_image (ximg);
/* X and W32 versions did it here, MAC version above. ++kfs
- img->width = width;
+ img->width = width;
img->height = height; */
UNGCPRO;
DEF_IMGLIB_FN (png_create_info_struct);
DEF_IMGLIB_FN (png_destroy_read_struct);
DEF_IMGLIB_FN (png_set_read_fn);
-DEF_IMGLIB_FN (png_init_io);
DEF_IMGLIB_FN (png_set_sig_bytes);
DEF_IMGLIB_FN (png_read_info);
DEF_IMGLIB_FN (png_get_IHDR);
DEF_IMGLIB_FN (png_error);
static int
-init_png_functions (void)
+init_png_functions (Lisp_Object libraries)
{
HMODULE library;
- /* Ensure zlib is loaded. Try debug version first. */
- if (!LoadLibrary ("zlibd.dll")
- && !LoadLibrary ("zlib.dll"))
- return 0;
-
/* Try loading libpng under probable names. */
- if (!(library = LoadLibrary ("libpng13d.dll"))
- && !(library = LoadLibrary ("libpng13.dll"))
- && !(library = LoadLibrary ("libpng12d.dll"))
- && !(library = LoadLibrary ("libpng12.dll"))
- && !(library = LoadLibrary ("libpng.dll")))
+ if (!(library = w32_delayed_load (libraries, Qpng)))
return 0;
LOAD_IMGLIB_FN (library, png_get_io_ptr);
LOAD_IMGLIB_FN (library, png_create_info_struct);
LOAD_IMGLIB_FN (library, png_destroy_read_struct);
LOAD_IMGLIB_FN (library, png_set_read_fn);
- LOAD_IMGLIB_FN (library, png_init_io);
LOAD_IMGLIB_FN (library, png_set_sig_bytes);
LOAD_IMGLIB_FN (library, png_read_info);
LOAD_IMGLIB_FN (library, png_get_IHDR);
#define fn_png_create_info_struct png_create_info_struct
#define fn_png_destroy_read_struct png_destroy_read_struct
#define fn_png_set_read_fn png_set_read_fn
-#define fn_png_init_io png_init_io
#define fn_png_set_sig_bytes png_set_sig_bytes
#define fn_png_read_info png_read_info
#define fn_png_get_IHDR png_get_IHDR
tbr->index = tbr->index + length;
}
+
+/* Function set as reader function when reading PNG image from a file.
+ PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
+ bytes from the input to DATA. */
+
+static void
+png_read_from_file (png_ptr, data, length)
+ png_structp png_ptr;
+ png_bytep data;
+ png_size_t length;
+{
+ FILE *fp = (FILE *) fn_png_get_io_ptr (png_ptr);
+
+ if (fread (data, 1, length, fp) < length)
+ fn_png_error (png_ptr, "Read error");
+}
+
+
/* Load PNG image IMG for use on frame F. Value is non-zero if
successful. */
tbr.bytes += sizeof (sig);
}
- /* Initialize read and info structs for PNG lib. */
- png_ptr = fn_png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
- my_png_error, my_png_warning);
+ /* Initialize read and info structs for PNG lib. Casting return
+ value avoids a GCC warning on W32. */
+ png_ptr = (png_structp)fn_png_create_read_struct (PNG_LIBPNG_VER_STRING,
+ NULL, my_png_error,
+ my_png_warning);
if (!png_ptr)
{
if (fp) fclose (fp);
return 0;
}
- info_ptr = fn_png_create_info_struct (png_ptr);
+ /* Casting return value avoids a GCC warning on W32. */
+ info_ptr = (png_infop)fn_png_create_info_struct (png_ptr);
if (!info_ptr)
{
fn_png_destroy_read_struct (&png_ptr, NULL, NULL);
return 0;
}
- end_info = fn_png_create_info_struct (png_ptr);
+ /* Casting return value avoids a GCC warning on W32. */
+ end_info = (png_infop)fn_png_create_info_struct (png_ptr);
if (!end_info)
{
fn_png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
if (!NILP (specified_data))
fn_png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
else
- fn_png_init_io (png_ptr, fp);
+ fn_png_set_read_fn (png_ptr, (void *) fp, png_read_from_file);
fn_png_set_sig_bytes (png_ptr, sizeof sig);
fn_png_read_info (png_ptr, info_ptr);
fn_png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
+ if (!check_image_size (f, width, height))
+ goto error;
+
/* If image contains simply transparency data, we prefer to
construct a clipping mask. */
if (fn_png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
png_color_16 user_bg;
bzero (&user_bg, sizeof user_bg);
- user_bg.red = color.red >> PNG_BG_COLOR_SHIFT;
- user_bg.green = color.green >> PNG_BG_COLOR_SHIFT;
- user_bg.blue = color.blue >> PNG_BG_COLOR_SHIFT;
+ user_bg.red = color.red >> 8;
+ user_bg.green = color.green >> 8;
+ user_bg.blue = color.blue >> 8;
fn_png_set_background (png_ptr, &user_bg,
PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
x_query_color (f, &color);
bzero (&frame_background, sizeof frame_background);
- frame_background.red = color.red;
- frame_background.green = color.green;
- frame_background.blue = color.blue;
+ frame_background.red = color.red >> 8;
+ frame_background.green = color.green >> 8;
+ frame_background.blue = color.blue >> 8;
#endif /* HAVE_X_WINDOWS */
#ifdef HAVE_NTGUI
x_query_color (f, &color);
#endif
bzero (&frame_background, sizeof frame_background);
- frame_background.red = 256 * GetRValue (color);
- frame_background.green = 256 * GetGValue (color);
- frame_background.blue = 256 * GetBValue (color);
+ frame_background.red = GetRValue (color);
+ frame_background.green = GetGValue (color);
+ frame_background.blue = GetBValue (color);
#endif /* HAVE_NTGUI */
#ifdef MAC_OS
if (channels == 4)
{
if (mask_img)
- XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW (f) : PIX_MASK_RETAIN (f));
+ XPutPixel (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
++p;
}
}
img->width = width;
img->height = height;
- /* Maybe fill in the background field while we have ximg handy. */
- IMAGE_BACKGROUND (img, f, ximg);
+ /* Maybe fill in the background field while we have ximg handy.
+ Casting avoids a GCC warning. */
+ IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
/* Put the image into the pixmap, then free the X image and its buffer. */
x_put_x_image (f, ximg, img->pixmap, width, height);
/* Same for the mask. */
if (mask_img)
{
- /* Fill in the background_transparent field while we have the mask
- handy. */
- image_background_transparent (img, f, mask_img);
+ /* Fill in the background_transparent field while we have the
+ mask handy. Casting avoids a GCC warning. */
+ image_background_transparent (img, f, (XImagePtr_or_DC)mask_img);
x_put_x_image (f, mask_img, img->mask, img->width, img->height);
x_destroy_x_image (mask_img);
#undef HAVE_STDLIB_H
#endif /* HAVE_STLIB_H */
+#if defined (HAVE_NTGUI) && !defined (__WIN32__)
+/* In older releases of the jpeg library, jpeglib.h will define boolean
+ differently depending on __WIN32__, so make sure it is defined. */
+#define __WIN32__ 1
+#endif
+
#include <jpeglib.h>
#include <jerror.h>
#include <setjmp.h>
DEF_IMGLIB_FN (jpeg_destroy_decompress);
DEF_IMGLIB_FN (jpeg_read_header);
DEF_IMGLIB_FN (jpeg_read_scanlines);
-DEF_IMGLIB_FN (jpeg_stdio_src);
DEF_IMGLIB_FN (jpeg_std_error);
DEF_IMGLIB_FN (jpeg_resync_to_restart);
static int
-init_jpeg_functions (void)
+init_jpeg_functions (Lisp_Object libraries)
{
HMODULE library;
- if (!(library = LoadLibrary ("libjpeg.dll"))
- && !(library = LoadLibrary ("jpeg-62.dll"))
- && !(library = LoadLibrary ("jpeg.dll")))
+ if (!(library = w32_delayed_load (libraries, Qjpeg)))
return 0;
LOAD_IMGLIB_FN (library, jpeg_finish_decompress);
LOAD_IMGLIB_FN (library, jpeg_read_scanlines);
LOAD_IMGLIB_FN (library, jpeg_start_decompress);
LOAD_IMGLIB_FN (library, jpeg_read_header);
- LOAD_IMGLIB_FN (library, jpeg_stdio_src);
LOAD_IMGLIB_FN (library, jpeg_CreateDecompress);
LOAD_IMGLIB_FN (library, jpeg_destroy_decompress);
LOAD_IMGLIB_FN (library, jpeg_std_error);
#define fn_jpeg_destroy_decompress jpeg_destroy_decompress
#define fn_jpeg_read_header jpeg_read_header
#define fn_jpeg_read_scanlines jpeg_read_scanlines
-#define fn_jpeg_stdio_src jpeg_stdio_src
#define fn_jpeg_std_error jpeg_std_error
#define jpeg_resync_to_restart_wrapper jpeg_resync_to_restart
libjpeg.doc from the JPEG lib distribution. */
static void
-our_init_source (cinfo)
+our_common_init_source (cinfo)
+ j_decompress_ptr cinfo;
+{
+}
+
+
+/* Method to terminate data source. Called by
+ jpeg_finish_decompress() after all data has been processed. */
+
+static void
+our_common_term_source (cinfo)
j_decompress_ptr cinfo;
{
}
so this only adds a fake end of input marker at the end. */
static boolean
-our_fill_input_buffer (cinfo)
+our_memory_fill_input_buffer (cinfo)
j_decompress_ptr cinfo;
{
/* Insert a fake EOI marker. */
src->next_input_byte = buffer;
src->bytes_in_buffer = 2;
- return TRUE;
+ return 1;
}
is the JPEG data source manager. */
static void
-our_skip_input_data (cinfo, num_bytes)
+our_memory_skip_input_data (cinfo, num_bytes)
j_decompress_ptr cinfo;
long num_bytes;
{
}
-/* Method to terminate data source. Called by
- jpeg_finish_decompress() after all data has been processed. */
-
-static void
-our_term_source (cinfo)
- j_decompress_ptr cinfo;
-{
-}
-
-
/* Set up the JPEG lib for reading an image from DATA which contains
LEN bytes. CINFO is the decompression info structure created for
reading the image. */
}
src = (struct jpeg_source_mgr *) cinfo->src;
- src->init_source = our_init_source;
- src->fill_input_buffer = our_fill_input_buffer;
- src->skip_input_data = our_skip_input_data;
+ src->init_source = our_common_init_source;
+ src->fill_input_buffer = our_memory_fill_input_buffer;
+ src->skip_input_data = our_memory_skip_input_data;
src->resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
- src->term_source = our_term_source;
+ src->term_source = our_common_term_source;
src->bytes_in_buffer = len;
src->next_input_byte = data;
}
+struct jpeg_stdio_mgr
+{
+ struct jpeg_source_mgr mgr;
+ boolean finished;
+ FILE *file;
+ JOCTET *buffer;
+};
+
+
+/* Size of buffer to read JPEG from file.
+ Not too big, as we want to use alloc_small. */
+#define JPEG_STDIO_BUFFER_SIZE 8192
+
+
+/* Fill input buffer method for JPEG data source manager. Called
+ whenever more data is needed. The data is read from a FILE *. */
+
+static boolean
+our_stdio_fill_input_buffer (cinfo)
+ j_decompress_ptr cinfo;
+{
+ struct jpeg_stdio_mgr *src;
+
+ src = (struct jpeg_stdio_mgr *) cinfo->src;
+ if (!src->finished)
+ {
+ size_t bytes;
+
+ bytes = fread (src->buffer, 1, JPEG_STDIO_BUFFER_SIZE, src->file);
+ if (bytes > 0)
+ src->mgr.bytes_in_buffer = bytes;
+ else
+ {
+ WARNMS (cinfo, JWRN_JPEG_EOF);
+ src->finished = 1;
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ src->mgr.bytes_in_buffer = 2;
+ }
+ src->mgr.next_input_byte = src->buffer;
+ }
+
+ return 1;
+}
+
+
+/* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
+ is the JPEG data source manager. */
+
+static void
+our_stdio_skip_input_data (cinfo, num_bytes)
+ j_decompress_ptr cinfo;
+ long num_bytes;
+{
+ struct jpeg_stdio_mgr *src;
+ src = (struct jpeg_stdio_mgr *) cinfo->src;
+
+ while (num_bytes > 0 && !src->finished)
+ {
+ if (num_bytes <= src->mgr.bytes_in_buffer)
+ {
+ src->mgr.bytes_in_buffer -= num_bytes;
+ src->mgr.next_input_byte += num_bytes;
+ break;
+ }
+ else
+ {
+ num_bytes -= src->mgr.bytes_in_buffer;
+ src->mgr.bytes_in_buffer = 0;
+ src->mgr.next_input_byte = NULL;
+
+ our_stdio_fill_input_buffer (cinfo);
+ }
+ }
+}
+
+
+/* Set up the JPEG lib for reading an image from a FILE *.
+ CINFO is the decompression info structure created for
+ reading the image. */
+
+static void
+jpeg_file_src (cinfo, fp)
+ j_decompress_ptr cinfo;
+ FILE *fp;
+{
+ struct jpeg_stdio_mgr *src;
+
+ if (cinfo->src != NULL)
+ src = (struct jpeg_stdio_mgr *) cinfo->src;
+ else
+ {
+ /* First time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof (struct jpeg_stdio_mgr));
+ src = (struct jpeg_stdio_mgr *) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ JPEG_STDIO_BUFFER_SIZE);
+ }
+
+ src->file = fp;
+ src->finished = 0;
+ src->mgr.init_source = our_common_init_source;
+ src->mgr.fill_input_buffer = our_stdio_fill_input_buffer;
+ src->mgr.skip_input_data = our_stdio_skip_input_data;
+ src->mgr.resync_to_restart = jpeg_resync_to_restart_wrapper; /* Use default method. */
+ src->mgr.term_source = our_common_term_source;
+ src->mgr.bytes_in_buffer = 0;
+ src->mgr.next_input_byte = NULL;
+}
+
+
/* Load image IMG for use on frame F. Patterned after example.c
from the JPEG lib. */
}
/* Customize libjpeg's error handling to call my_error_exit when an
- error is detected. This function will perform a longjmp. */
- cinfo.err = fn_jpeg_std_error (&mgr.pub);
+ error is detected. This function will perform a longjmp.
+ Casting return value avoids a GCC warning on W32. */
+ cinfo.err = (struct jpeg_error_mgr *)fn_jpeg_std_error (&mgr.pub);
mgr.pub.error_exit = my_error_exit;
if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
fn_jpeg_CreateDecompress (&cinfo, JPEG_LIB_VERSION, sizeof (cinfo));
if (NILP (specified_data))
- fn_jpeg_stdio_src (&cinfo, (FILE *) fp);
+ jpeg_file_src (&cinfo, (FILE *) fp);
else
jpeg_memory_src (&cinfo, SDATA (specified_data),
SBYTES (specified_data));
- fn_jpeg_read_header (&cinfo, TRUE);
+ fn_jpeg_read_header (&cinfo, 1);
/* Customize decompression so that color quantization will be used.
Start decompression. */
- cinfo.quantize_colors = TRUE;
+ cinfo.quantize_colors = 1;
fn_jpeg_start_decompress (&cinfo);
width = img->width = cinfo.output_width;
height = img->height = cinfo.output_height;
+ if (!check_image_size (f, width, height))
+ {
+ image_error ("Invalid image size", Qnil, Qnil);
+ longjmp (mgr.setjmp_buffer, 2);
+ }
+
/* Create X image and pixmap. */
if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
longjmp (mgr.setjmp_buffer, 2);
/* Maybe fill in the background field while we have ximg handy. */
if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
- IMAGE_BACKGROUND (img, f, ximg);
+ /* Casting avoids a GCC warning. */
+ IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
/* Put the image into the pixmap. */
x_put_x_image (f, ximg, img->pixmap, width, height);
DEF_IMGLIB_FN (TIFFClose);
static int
-init_tiff_functions (void)
+init_tiff_functions (Lisp_Object libraries)
{
HMODULE library;
- if (!(library = LoadLibrary ("libtiff.dll")))
+ if (!(library = w32_delayed_load (libraries, Qtiff)))
return 0;
LOAD_IMGLIB_FN (library, TIFFSetErrorHandler);
return 0;
}
- /* Try to open the image file. */
- tiff = fn_TIFFOpen (SDATA (file), "r");
+ /* Try to open the image file. Casting return value avoids a
+ GCC warning on W32. */
+ tiff = (TIFF *)fn_TIFFOpen (SDATA (file), "r");
if (tiff == NULL)
{
image_error ("Cannot open `%s'", file, Qnil);
memsrc.len = SBYTES (specified_data);
memsrc.index = 0;
- tiff = fn_TIFFClientOpen ("memory_source", "r", &memsrc,
- (TIFFReadWriteProc) tiff_read_from_memory,
- (TIFFReadWriteProc) tiff_write_from_memory,
- tiff_seek_in_memory,
- tiff_close_memory,
- tiff_size_of_memory,
- tiff_mmap_memory,
- tiff_unmap_memory);
+ /* Casting return value avoids a GCC warning on W32. */
+ tiff = (TIFF *)fn_TIFFClientOpen ("memory_source", "r", &memsrc,
+ (TIFFReadWriteProc) tiff_read_from_memory,
+ (TIFFReadWriteProc) tiff_write_from_memory,
+ tiff_seek_in_memory,
+ tiff_close_memory,
+ tiff_size_of_memory,
+ tiff_mmap_memory,
+ tiff_unmap_memory);
if (!tiff)
{
of width x height 32-bit values. */
fn_TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
fn_TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
+
+ if (!check_image_size (f, width, height))
+ {
+ image_error ("Invalid image size", Qnil, Qnil);
+ UNGCPRO;
+ return 0;
+ }
+
buf = (uint32 *) xmalloc (width * height * sizeof *buf);
rc = fn_TIFFReadRGBAImage (tiff, width, height, buf, 0);
/* Maybe fill in the background field while we have ximg handy. */
if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
- IMAGE_BACKGROUND (img, f, ximg);
+ /* Casting avoids a GCC warning on W32. */
+ IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
/* Put the image into the pixmap, then free the X image and its buffer. */
x_put_x_image (f, ximg, img->pixmap, width, height);
#ifdef HAVE_GIF
#if defined (HAVE_NTGUI) || defined (MAC_OS)
+/* winuser.h might define DrawText to DrawTextA or DrawTextW.
+ Undefine before redefining to avoid a preprocessor warning. */
+#ifdef DrawText
+#undef DrawText
+#endif
/* avoid conflict with QuickdrawText.h */
#define DrawText gif_DrawText
#include <gif_lib.h>
DEF_IMGLIB_FN (DGifOpenFileName);
static int
-init_gif_functions (void)
+init_gif_functions (Lisp_Object libraries)
{
HMODULE library;
- if (!(library = LoadLibrary ("libungif.dll")))
+ if (!(library = w32_delayed_load (libraries, Qgif)))
return 0;
LOAD_IMGLIB_FN (library, DGifCloseFile);
return 0;
}
- /* Open the GIF file. */
- gif = fn_DGifOpenFileName (SDATA (file));
+ /* Open the GIF file. Casting return value avoids a GCC warning
+ on W32. */
+ gif = (GifFileType *)fn_DGifOpenFileName (SDATA (file));
if (gif == NULL)
{
image_error ("Cannot open `%s'", file, Qnil);
memsrc.len = SBYTES (specified_data);
memsrc.index = 0;
- gif = fn_DGifOpen(&memsrc, gif_read_from_memory);
+ /* Casting return value avoids a GCC warning on W32. */
+ gif = (GifFileType *)fn_DGifOpen(&memsrc, gif_read_from_memory);
if (!gif)
{
image_error ("Cannot open memory source `%s'", img->spec, Qnil);
}
}
+ /* Before reading entire contents, check the declared image size. */
+ if (!check_image_size (f, gif->SWidth, gif->SHeight))
+ {
+ image_error ("Invalid image size", Qnil, Qnil);
+ fn_DGifCloseFile (gif);
+ UNGCPRO;
+ return 0;
+ }
+
/* Read entire contents. */
rc = fn_DGifSlurp (gif);
if (rc == GIF_ERROR)
return 0;
}
- width = img->width = max (gif->SWidth, gif->Image.Left + gif->Image.Width);
- height = img->height = max (gif->SHeight, gif->Image.Top + gif->Image.Height);
+ image_top = gif->SavedImages[ino].ImageDesc.Top;
+ image_left = gif->SavedImages[ino].ImageDesc.Left;
+ image_width = gif->SavedImages[ino].ImageDesc.Width;
+ image_height = gif->SavedImages[ino].ImageDesc.Height;
+
+ width = img->width = max (gif->SWidth,
+ max (gif->Image.Left + gif->Image.Width,
+ image_left + image_width));
+ height = img->height = max (gif->SHeight,
+ max (gif->Image.Top + gif->Image.Height,
+ image_top + image_height));
+
+ if (!check_image_size (f, width, height))
+ {
+ image_error ("Invalid image size", Qnil, Qnil);
+ fn_DGifCloseFile (gif);
+ UNGCPRO;
+ return 0;
+ }
/* Create the X image and pixmap. */
if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
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. */
- image_top = gif->SavedImages[ino].ImageDesc.Top;
- image_left = gif->SavedImages[ino].ImageDesc.Left;
- image_width = gif->SavedImages[ino].ImageDesc.Width;
- image_height = gif->SavedImages[ino].ImageDesc.Height;
-
for (y = 0; y < image_top; ++y)
for (x = 0; x < width; ++x)
XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
/* Maybe fill in the background field while we have ximg handy. */
if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
- IMAGE_BACKGROUND (img, f, ximg);
+ /* Casting avoids a GCC warning. */
+ IMAGE_BACKGROUND (img, f, (XImagePtr_or_DC)ximg);
/* Put the image into the pixmap, then free the X image and its buffer. */
x_put_x_image (f, ximg, img->pixmap, width, height);
return 1;
}
-#else
+#else /* !HAVE_GIF */
#ifdef MAC_OS
static int
TimeValue time;
struct gcpro gcpro1;
int ino;
+ CGrafPtr old_port;
+ GDHandle old_gdh;
specified_file = image_spec_value (img->spec, QCfile, NULL);
specified_data = image_spec_value (img->spec, QCdata, NULL);
if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
goto error;
+ GetGWorld (&old_port, &old_gdh);
SetGWorld (ximg, NULL);
bg_color.red = color.red;
bg_color.green = color.green;
bg_color.blue = color.blue;
RGBBackColor (&bg_color);
- SetMovieActive (movie, TRUE);
+ SetGWorld (old_port, old_gdh);
+ SetMovieActive (movie, 1);
SetMovieGWorld (movie, ximg, NULL);
SampleNumToMediaTime (media, ino + 1, &time, NULL);
SetMovieTimeValue (movie, time);
in_height = XFASTINT (pt_height) / 72.0;
img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
+ if (!check_image_size (f, img->width, img->height))
+ {
+ image_error ("Invalid image size", Qnil, Qnil);
+ return 0;
+ }
+
/* Create the pixmap. */
xassert (img->pixmap == NO_PIXMAP);
Initialization
***********************************************************************/
+#ifdef HAVE_NTGUI
+/* Image types that rely on external libraries are loaded dynamically
+ if the library is available. */
+#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
+ define_image_type (image_type, init_lib_fn (libraries))
+#else
+#define CHECK_LIB_AVAILABLE(image_type, init_lib_fn, libraries) \
+ define_image_type (image_type, 1)
+#endif /* HAVE_NTGUI */
+
+DEFUN ("init-image-library", Finit_image_library, Sinit_image_library, 2, 2, 0,
+ doc: /* Initialize image library implementing image type TYPE.
+Return non-nil if TYPE is a supported image type.
+
+Image types pbm and xbm are prebuilt; other types are loaded here.
+Libraries to load are specified in alist LIBRARIES (usually, the value
+of `image-library-alist', which see). */)
+ (type, libraries)
+ Lisp_Object type, libraries;
+{
+ Lisp_Object tested;
+
+ /* Don't try to reload the library. */
+ tested = Fassq (type, Vimage_type_cache);
+ if (CONSP (tested))
+ return XCDR (tested);
+
+#if defined (HAVE_XPM) || defined (MAC_OS)
+ if (EQ (type, Qxpm))
+ return CHECK_LIB_AVAILABLE (&xpm_type, init_xpm_functions, libraries);
+#endif
+
+#if defined (HAVE_JPEG) || defined (MAC_OS)
+ if (EQ (type, Qjpeg))
+ return CHECK_LIB_AVAILABLE (&jpeg_type, init_jpeg_functions, libraries);
+#endif
+
+#if defined (HAVE_TIFF) || defined (MAC_OS)
+ if (EQ (type, Qtiff))
+ return CHECK_LIB_AVAILABLE (&tiff_type, init_tiff_functions, libraries);
+#endif
+
+#if defined (HAVE_GIF) || defined (MAC_OS)
+ if (EQ (type, Qgif))
+ return CHECK_LIB_AVAILABLE (&gif_type, init_gif_functions, libraries);
+#endif
+
+#if defined (HAVE_PNG) || defined (MAC_OS)
+ if (EQ (type, Qpng))
+ return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
+#endif
+
+#ifdef HAVE_GHOSTSCRIPT
+ if (EQ (type, Qpostscript))
+ return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
+#endif
+
+ /* If the type is not recognized, avoid testing it ever again. */
+ CACHE_IMAGE_TYPE (type, Qnil);
+ return Qnil;
+}
+
void
syms_of_image ()
{
+ extern Lisp_Object Qrisky_local_variable; /* Syms_of_xdisp has already run. */
+
+ /* Initialize this only once, since that's what we do with Vimage_types
+ and they are supposed to be in sync. Initializing here gives correct
+ operation on GNU/Linux of calling dump-emacs after loading some images. */
+ image_types = NULL;
+
+ /* Must be defined now becase we're going to update it below, while
+ defining the supported image types. */
+ DEFVAR_LISP ("image-types", &Vimage_types,
+ doc: /* List of potentially supported image types.
+Each element of the list is a symbol for a image type, like 'jpeg or 'png.
+To check whether it is really supported, use `image-type-available-p'. */);
+ Vimage_types = Qnil;
+
+ DEFVAR_LISP ("image-library-alist", &Vimage_library_alist,
+ doc: /* Alist of image types vs external libraries needed to display them.
+
+Each element is a list (IMAGE-TYPE LIBRARY...), where the car is a symbol
+representing a supported image type, and the rest are strings giving
+alternate filenames for the corresponding external libraries.
+
+Emacs tries to load the libraries in the order they appear on the
+list; if none is loaded, the running session of Emacs won't
+support the image type. Types 'pbm and 'xbm don't need to be
+listed; they're always supported. */);
+ Vimage_library_alist = Qnil;
+ Fput (intern ("image-library-alist"), Qrisky_local_variable, Qt);
+
+ DEFVAR_LISP ("max-image-size", &Vmax_image_size,
+ doc: /* Maximum size of images.
+Emacs will not load an image into memory if its pixel width or
+pixel height exceeds this limit.
+
+If the value is an integer, it directly specifies the maximum
+image height and width, measured in pixels. If it is a floating
+point number, it specifies the maximum image height and width
+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);
+
+ Vimage_type_cache = Qnil;
+ staticpro (&Vimage_type_cache);
+
+ Qpbm = intern ("pbm");
+ staticpro (&Qpbm);
+ ADD_IMAGE_TYPE(Qpbm);
+
+ Qxbm = intern ("xbm");
+ staticpro (&Qxbm);
+ ADD_IMAGE_TYPE(Qxbm);
+
+ define_image_type (&xbm_type, 1);
+ define_image_type (&pbm_type, 1);
+
QCascent = intern (":ascent");
staticpro (&QCascent);
QCmargin = intern (":margin");
staticpro (&Qedge_detection);
Qheuristic = intern ("heuristic");
staticpro (&Qheuristic);
- Qcenter = intern ("center");
- staticpro (&Qcenter);
Qpostscript = intern ("postscript");
staticpro (&Qpostscript);
#ifdef HAVE_GHOSTSCRIPT
+ ADD_IMAGE_TYPE(Qpostscript);
QCloader = intern (":loader");
staticpro (&QCloader);
QCbounding_box = intern (":bounding-box");
staticpro (&QCpt_height);
#endif /* HAVE_GHOSTSCRIPT */
- Qpbm = intern ("pbm");
- staticpro (&Qpbm);
-
- Qxbm = intern ("xbm");
- staticpro (&Qxbm);
-
-#ifdef HAVE_XPM
+#if defined (HAVE_XPM) || defined (MAC_OS)
Qxpm = intern ("xpm");
staticpro (&Qxpm);
+ ADD_IMAGE_TYPE(Qxpm);
#endif
#if defined (HAVE_JPEG) || defined (MAC_OS)
Qjpeg = intern ("jpeg");
staticpro (&Qjpeg);
+ ADD_IMAGE_TYPE(Qjpeg);
#endif
#if defined (HAVE_TIFF) || defined (MAC_OS)
Qtiff = intern ("tiff");
staticpro (&Qtiff);
+ ADD_IMAGE_TYPE(Qtiff);
#endif
#if defined (HAVE_GIF) || defined (MAC_OS)
Qgif = intern ("gif");
staticpro (&Qgif);
+ ADD_IMAGE_TYPE(Qgif);
#endif
#if defined (HAVE_PNG) || defined (MAC_OS)
Qpng = intern ("png");
staticpro (&Qpng);
+ ADD_IMAGE_TYPE(Qpng);
#endif
+ defsubr (&Sinit_image_library);
defsubr (&Sclear_image_cache);
defsubr (&Simage_size);
defsubr (&Simage_mask_p);
Vimage_cache_eviction_delay = make_number (30 * 60);
}
-
-#ifdef HAVE_NTGUI
-/* Image types that rely on external libraries are loaded dynamically
- if the library is available. */
-#define IF_LIB_AVAILABLE(init_lib_fn) if (init_lib_fn())
-#else
-#define IF_LIB_AVAILABLE(init_func) /* Load unconditionally */
-#endif /* HAVE_NTGUI */
-
void
init_image ()
{
- image_types = NULL;
- Vimage_types = Qnil;
-
- define_image_type (&xbm_type);
- define_image_type (&pbm_type);
-
-#ifdef HAVE_XPM
- IF_LIB_AVAILABLE(init_xpm_functions)
- define_image_type (&xpm_type);
-#endif
-
-#if defined (HAVE_JPEG) || defined (MAC_OS)
- IF_LIB_AVAILABLE(init_jpeg_functions)
- define_image_type (&jpeg_type);
-#endif
-
-#if defined (HAVE_TIFF) || defined (MAC_OS)
- IF_LIB_AVAILABLE(init_tiff_functions)
- define_image_type (&tiff_type);
-#endif
-
-#if defined (HAVE_GIF) || defined (MAC_OS)
- IF_LIB_AVAILABLE(init_gif_functions)
- define_image_type (&gif_type);
-#endif
-
-#if defined (HAVE_PNG) || defined (MAC_OS)
- IF_LIB_AVAILABLE(init_png_functions)
- define_image_type (&png_type);
-#endif
-
-#ifdef HAVE_GHOSTSCRIPT
- define_image_type (&gs_type);
-#endif
-
#ifdef MAC_OS
/* Animated gifs use QuickTime Movie Toolbox. So initialize it here. */
EnterMovies ();