]> code.delx.au - gnu-emacs/blobdiff - src/image.c
(msdos-shells): Add defvar.
[gnu-emacs] / src / image.c
index 3c53903b4b4cf88e9bf5fd3ae93b186a317064e1..3e8a62801b03b4fa4b58fa3050405e1362f90042 100644 (file)
@@ -1,6 +1,6 @@
 /* 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.
 
@@ -16,13 +16,13 @@ GNU General Public License for more details.
 
 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>
@@ -82,17 +82,24 @@ typedef struct w32_bitmap_record Bitmap_Record;
 
 #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
@@ -605,6 +612,18 @@ x_create_bitmap_mask (f, 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;
@@ -629,7 +648,7 @@ Lisp_Object Vimage_cache_eviction_delay;
 
 /* 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 *));
@@ -637,21 +656,37 @@ static void x_emboss 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;
 }
 
 
@@ -664,6 +699,10 @@ lookup_image_type (symbol)
 {
   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;
@@ -1596,11 +1635,6 @@ lookup_image (f, spec)
      Lisp_Object spec;
 {
   struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
-#ifdef _MSC_VER
-  /* Work around a problem with MinGW builds of graphics libraries
-     not honoring calling conventions.  */
-  static
-#endif
   struct image *img;
   int i;
   unsigned hash;
@@ -1780,7 +1814,7 @@ forall_images_in_image_cache (f, fn)
 #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) {                                     \
@@ -1788,6 +1822,33 @@ forall_images_in_image_cache (f, fn)
     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,
@@ -1911,7 +1972,8 @@ x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
      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);
@@ -2360,8 +2422,7 @@ image_load_quartz2d (f, img, png_p)
          UNGCPRO;
          return 0;
        }
-      path = CFStringCreateWithCString (NULL, SDATA (file),
-                                       kCFStringEncodingUTF8);
+      path = cfstring_create_with_string (file);
       url = CFURLCreateWithFileSystemPath (NULL, path,
                                           kCFURLPOSIXPathStyle, 0);
       CFRelease (path);
@@ -3488,13 +3549,12 @@ DEF_IMGLIB_FN (XpmCreateImageFromBuffer);
 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);
@@ -5458,7 +5518,8 @@ pbm_load (f, img)
   /* 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);
@@ -5570,7 +5631,6 @@ DEF_IMGLIB_FN (png_create_read_struct);
 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);
@@ -5588,21 +5648,12 @@ DEF_IMGLIB_FN (png_read_end);
 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);
@@ -5611,7 +5662,6 @@ init_png_functions (void)
   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);
@@ -5637,7 +5687,6 @@ init_png_functions (void)
 #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
@@ -5693,12 +5742,6 @@ struct png_memory_storage
    PNG_PTR is a pointer to the PNG control structure.  Copy LENGTH
    bytes from the input to DATA.  */
 
-#ifdef _MSC_VER
-  /* Work around a problem with MinGW builds of graphics libraries
-     not honoring calling conventions.  */
-#pragma optimize("g", off)
-#endif
-
 static void
 png_read_from_memory (png_ptr, data, length)
      png_structp png_ptr;
@@ -5715,10 +5758,23 @@ png_read_from_memory (png_ptr, data, length)
   tbr->index = tbr->index + length;
 }
 
-#ifdef _MSC_VER
-/* Restore normal optimization, as specified on the command line.  */
-#pragma optimize("", on)
-#endif
+
+/* 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.  */
@@ -5803,9 +5859,11 @@ png_load (f, img)
       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);
@@ -5813,7 +5871,8 @@ png_load (f, img)
       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);
@@ -5822,7 +5881,8 @@ png_load (f, img)
       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);
@@ -5849,7 +5909,7 @@ png_load (f, img)
   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);
@@ -6095,8 +6155,9 @@ png_load (f, img)
   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);
@@ -6105,9 +6166,9 @@ png_load (f, img)
   /* 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);
@@ -6224,6 +6285,12 @@ jpeg_image_p (object)
 #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>
@@ -6246,13 +6313,11 @@ 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);
@@ -6335,7 +6400,7 @@ our_fill_input_buffer (cinfo)
 
   src->next_input_byte = buffer;
   src->bytes_in_buffer = 2;
-  return TRUE;
+  return 1;
 }
 
 
@@ -6450,8 +6515,9 @@ jpeg_load (f, img)
     }
 
   /* 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)
@@ -6490,11 +6556,11 @@ jpeg_load (f, img)
     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;
@@ -6562,7 +6628,8 @@ jpeg_load (f, img)
 
   /* 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);
@@ -6683,11 +6750,11 @@ DEF_IMGLIB_FN (TIFFReadRGBAImage);
 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);
@@ -6888,8 +6955,9 @@ tiff_load (f, img)
          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);
@@ -6904,14 +6972,15 @@ tiff_load (f, img)
       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)
        {
@@ -6974,7 +7043,8 @@ tiff_load (f, img)
 
   /* 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);
@@ -7082,6 +7152,11 @@ gif_image_p (object)
 #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>
@@ -7103,11 +7178,11 @@ DEF_IMGLIB_FN (DGifOpen);
 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);
@@ -7195,8 +7270,9 @@ gif_load (f, img)
          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);
@@ -7212,7 +7288,8 @@ gif_load (f, img)
       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);
@@ -7346,7 +7423,8 @@ gif_load (f, img)
 
   /* 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);
@@ -7356,7 +7434,7 @@ gif_load (f, img)
   return 1;
 }
 
-#else
+#else  /* !HAVE_GIF */
 
 #ifdef MAC_OS
 static int
@@ -7509,7 +7587,7 @@ gif_load (f, img)
   bg_color.blue = color.blue;
   RGBBackColor (&bg_color);
   SetGWorld (old_port, old_gdh);
-  SetMovieActive (movie, TRUE);
+  SetMovieActive (movie, 1);
   SetMovieGWorld (movie, ximg, NULL);
   SampleNumToMediaTime (media, ino + 1, &time, NULL);
   SetMovieTimeValue (movie, time);
@@ -7880,9 +7958,114 @@ DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
                            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);
+
+  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");
@@ -7916,6 +8099,7 @@ syms_of_image ()
   Qpostscript = intern ("postscript");
   staticpro (&Qpostscript);
 #ifdef HAVE_GHOSTSCRIPT
+  ADD_IMAGE_TYPE(Qpostscript);
   QCloader = intern (":loader");
   staticpro (&QCloader);
   QCbounding_box = intern (":bounding-box");
@@ -7926,37 +8110,37 @@ syms_of_image ()
   staticpro (&QCpt_height);
 #endif /* HAVE_GHOSTSCRIPT */
 
-  Qpbm = intern ("pbm");
-  staticpro (&Qpbm);
-
-  Qxbm = intern ("xbm");
-  staticpro (&Qxbm);
-
 #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);
@@ -7984,53 +8168,9 @@ meaning don't clear the cache.  */);
   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);
-
-#if defined (HAVE_XPM) || defined (MAC_OS)
-  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 ();