diff src/glyphs-x.c @ 265:8efd647ea9ca r20-5b31

Import from CVS: tag r20-5b31
author cvs
date Mon, 13 Aug 2007 10:25:37 +0200
parents 11cf20601dec
children 966663fcf606
line wrap: on
line diff
--- a/src/glyphs-x.c	Mon Aug 13 10:24:47 2007 +0200
+++ b/src/glyphs-x.c	Mon Aug 13 10:25:37 2007 +0200
@@ -35,6 +35,10 @@
    Improved GIF/JPEG support added by Bill Perry for 19.14
    Cleanup/simplification of error handling by Ben Wing for 19.14
    Pointer/icon overhaul, more restructuring by Ben Wing for 19.14
+   GIF support changed to external GIFlib 3.1 by Jareth Hein for 20.5
+   Many changes for color work and optimizations by Jareth Hein for 20.5
+   Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 20.5
+   TIFF code by Jareth Hein for 20.5
 
    TODO:
    Convert images.el to C and stick it in here?
@@ -53,6 +57,8 @@
 #include "insdel.h"
 #include "opaque.h"
 
+#include "imgproc.h"
+
 #include "sysfile.h"
 
 #ifdef HAVE_PNG
@@ -70,8 +76,17 @@
 #include "file-coding.h"
 #endif
 
-#define LISP_DEVICE_TO_X_SCREEN(dev)					\
-  XDefaultScreenOfDisplay (DEVICE_X_DISPLAY (XDEVICE (dev)))
+#if INTBITS == 32
+# define FOUR_BYTE_TYPE unsigned int
+#elif LONGBITS == 32
+# define FOUR_BYTE_TYPE unsigned long
+#elif SHORTBITS == 32
+# define FOUR_BYTE_TYPE unsigned short
+#else
+#error What kind of strange-ass system are we running on?
+#endif
+
+#define LISP_DEVICE_TO_X_SCREEN(dev) XDefaultScreenOfDisplay (DEVICE_X_DISPLAY (XDEVICE (dev)))
 
 DEFINE_IMAGE_INSTANTIATOR_FORMAT (xbm);
 Lisp_Object Qxbm;
@@ -131,6 +146,165 @@
 /*                      image instance methods                          */
 /************************************************************************/
 
+/************************************************************************/
+/* convert from a series of RGB triples to an XImage formated for the   */
+/* proper display 							*/
+/************************************************************************/
+XImage *EImage2XImage(Lisp_Object device, int width, int height, unsigned char *pic,
+		      unsigned long **pixtbl, int *pixcount, int *npixels)
+{
+  Display *dpy;
+  Colormap cmap;
+  Visual *vis;
+  XImage *outimg;
+  int depth, bitmap_pad, byte_cnt, i, j;
+  int rd,gr,bl,q;
+  unsigned char *data, *ip, *dp;
+  quant_table *qtable;
+  union {
+    FOUR_BYTE_TYPE val;
+    char cp[4];
+  } conv;
+
+  dpy = DEVICE_X_DISPLAY (XDEVICE (device));
+  cmap = DEVICE_X_COLORMAP (XDEVICE(device));
+  vis = DEVICE_X_VISUAL (XDEVICE(device));
+  depth = DEVICE_X_DEPTH(XDEVICE(device));
+
+  if (vis->class == PseudoColor) {
+    /* Quantize the image and get a histogram while we're at it.
+       Do this first to save memory */
+    qtable = EImage_build_quantable(pic, width, height, 256);
+    if (qtable == NULL) return NULL;
+  }
+
+  bitmap_pad = ((depth > 16) ? 32 :
+		(depth >  8) ? 16 :
+		8);
+  byte_cnt = bitmap_pad >> 3;
+  
+  outimg = XCreateImage (dpy, vis,
+			 depth, ZPixmap, 0, 0, width, height,
+			 bitmap_pad, 0);
+  if (!outimg) return NULL;
+
+  data = (unsigned char *) xmalloc (outimg->bytes_per_line * height);
+  if (!data) {
+    XDestroyImage(outimg);
+    return NULL;
+  }
+  outimg->data = data;
+  
+  if (vis->class == PseudoColor) {
+    unsigned long pixarray[256];
+    int n;
+    /* use our quantize table to allocate the colors */
+    *pixcount = 32;
+    *pixtbl = xnew_array (unsigned long, *pixcount);
+    *npixels = 0;
+
+    /* ### should implement a sort by popularity to assure proper allocation */
+    n = *npixels;
+    for (i = 0; i < qtable->num_active_colors; i++) {
+	XColor color;
+	int res;
+	
+	color.red = qtable->rm[i] ? qtable->rm[i] << 8 : 0;
+	color.green = qtable->gm[i] ? qtable->gm[i] << 8 : 0;
+	color.blue = qtable->bm[i] ? qtable->bm[i] << 8 : 0;
+	color.flags = DoRed | DoGreen | DoBlue;
+	res = allocate_nearest_color (dpy, cmap, vis, &color);
+	if (res > 0 && res < 3)
+	  {
+	    DO_REALLOC(*pixtbl, *pixcount, n+1, unsigned long);
+	    (*pixtbl)[n] = color.pixel;
+	    n++;
+	  }
+	pixarray[i] = color.pixel;
+    }
+    *npixels = n;
+    ip = pic;
+    for (i = 0; i < height; i++) {
+      dp = data + (i * outimg->bytes_per_line);
+      for (j = 0; j < width; j++) {
+	rd = *ip++;
+	gr = *ip++;
+	bl = *ip++;
+	conv.val = pixarray[QUANT_GET_COLOR(qtable,rd,gr,bl)];
+#ifdef WORDS_BIGENDIAN
+	for (q = 4-byte_cnt; q < 4; q++) *dp++ = conv.cp[q];
+#else
+	for (q = 0; q < byte_cnt; q++) *dp++ = conv.cp[q];
+#endif
+      }
+    }
+    xfree(qtable);
+  } else {
+    unsigned long rshift,gshift,bshift,rbits,gbits,bbits,junk;
+    junk = vis->red_mask;
+    rshift = 0;
+    while ((junk & 0x1) == 0) {
+      junk = junk >> 1;
+      rshift ++;
+    }
+    rbits = 0;
+    while (junk != 0) {
+      junk = junk >> 1;
+      rbits++;
+    }
+    junk = vis->green_mask;
+    gshift = 0;
+    while ((junk & 0x1) == 0) {
+      junk = junk >> 1;
+      gshift ++;
+    }
+    gbits = 0;
+    while (junk != 0) {
+      junk = junk >> 1;
+      gbits++;
+    }
+    junk = vis->blue_mask;
+    bshift = 0;
+    while ((junk & 0x1) == 0) {
+      junk = junk >> 1;
+      bshift ++;
+    }
+    bbits = 0;
+    while (junk != 0) {
+      junk = junk >> 1;
+      bbits++;
+    }
+    ip = pic;
+    for (i = 0; i < height; i++) {
+      dp = data + (i * outimg->bytes_per_line);
+      for (j = 0; j < width; j++) {
+	if (rbits > 8)
+	  rd = *ip++ << (rbits - 8);
+	else
+	  rd = *ip++ >> (8 - rbits);
+	if (gbits > 8)
+	  gr = *ip++ << (gbits - 8);
+	else
+	  gr = *ip++ >> (8 - gbits);
+	if (bbits > 8)
+	  bl = *ip++ << (bbits - 8);
+	else
+	  bl = *ip++ >> (8 - bbits);
+
+	conv.val = (rd << rshift) | (gr << gshift) | (bl << bshift);
+#ifdef WORDS_BIGENDIAN
+	for (q = 4-byte_cnt; q < 4; q++) *dp++ = conv.cp[q];
+#else
+	for (q = 0; q < byte_cnt; q++) *dp++ = conv.cp[q];
+#endif
+      }
+    }
+  }  
+  return outimg;
+}
+
+
+
 static void
 x_print_image_instance (struct Lisp_Image_Instance *p,
 			Lisp_Object printcharfun,
@@ -340,7 +514,7 @@
 	  && !strcmp (type, "String"))
 	Vx_bitmap_file_path = decode_env_path (0, (char *) value.addr);
       Vx_bitmap_file_path = nconc2 (Vx_bitmap_file_path,
-				    (list1 (build_string (BITMAPDIR))));
+				    (decode_path (BITMAPDIR)));
     }
 
   {
@@ -440,6 +614,7 @@
   }
 }
 
+#if 0
 static void
 write_lisp_string_to_temp_file (Lisp_Object string, char *filename_out)
 {
@@ -448,7 +623,7 @@
   char tempbuf[1024]; /* some random amount */
   int fubar = 0;
   FILE *tmpfil;
-  static Extbyte_dynarr *conversion_out_dynarr = NULL;
+  static Extbyte_dynarr *conversion_out_dynarr;
   Bytecount bstart, bend;
   struct gcpro gcpro1, gcpro2;
 #ifdef FILE_CODING
@@ -539,6 +714,7 @@
     report_file_error ("Writing temp file",
 		       list1 (build_string (filename_out)));
 }
+#endif
 
 
 /************************************************************************/
@@ -1803,14 +1979,18 @@
   FILE *instream;
   /* Object that holds state info for JPEG decoding */
   struct jpeg_decompress_struct *cinfo_ptr;
+  /* EImage data */
+  unsigned char *eimage;
   /* Pixels to keep around while the image is active */
   unsigned long *pixels;
-  int npixels;
+  int npixels, pixcount;
   /* Client-side image structure */
   XImage *ximage;
   /* Tempfile to remove */
+#ifdef USE_TEMP_FILES_FOR_JPEG_IMAGES
   char tempfile[50];
   int tempfile_needs_to_be_removed;
+#endif
 };
 
 static Lisp_Object
@@ -1826,14 +2006,12 @@
   if (data->instream)
     fclose (data->instream);
 
-  if (data->tempfile_needs_to_be_removed)
-    unlink (data->tempfile);
+  if (data->eimage) xfree (data->eimage);
 
   if (data->npixels > 0)
-    {
       XFreeColors (data->dpy, data->cmap, data->pixels, data->npixels, 0L);
+  if (data->pixcount)
       xfree (data->pixels);
-    }
 
   if (data->ximage)
     {
@@ -1844,6 +2022,10 @@
         }
       XDestroyImage (data->ximage);
     }
+#if USE_TEMP_FILES_FOR_JPEG_IMAGES
+  if (data->tempfile_needs_to_be_removed)
+    unlink (data->tempfile);
+#endif
 
   return Qnil;
 }
@@ -1982,7 +2164,6 @@
   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
   Display *dpy;
-  Screen *scr;
   Colormap cmap;
   Visual *vis;
   /* It is OK for the unwind data to be local to this function,
@@ -2005,7 +2186,6 @@
     signal_simple_error ("Not an X device", device);
 
   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
-  scr = DefaultScreenOfDisplay (dpy);
   cmap = DEVICE_X_COLORMAP (XDEVICE(device));
   vis = DEVICE_X_VISUAL (XDEVICE(device));
 
@@ -2098,32 +2278,37 @@
    * See libjpeg.doc for more info.
    */
 
+#if 0
   /* Step 4: set parameters for decompression.   */
 
-  /* We request that the JPEG file be automatically quantized into
-     8-bit color in case it's not already (many JPEGs are stored in
-     24-bit color).  "Two-pass quantize" means that the colormap
-     is determined on-the-fly for this particular image rather than
-     quantizing to a supplied colormap.  We can get away with this
-     because we then use allocate_nearest_color().
-
-     #### Note of course that this is not the most color-effective
-     way of doing things -- we could quantize an image that has
-     lots of very similar colors, and eat up the colormap with these
-     (useless to other images) colors.  Unfortunately I don't think
-     there's any "general" way of maximizing the overall image
-     quality of lots of images, given that we don't know the
-     colors of the images until we come across each one.  Best we
-     could do would be various sorts of heuristics, which I don't
-     feel like dealing with now.  A better scheme would be the
-     way things are done under MS Windows, where the colormap is
-     dynamically adjusted for various applications; but that kind
-     of thing would have to be provided by X, which it isn't. */
-
-  cinfo.quantize_colors = TRUE;
-  cinfo.two_pass_quantize = TRUE;
-  cinfo.colormap = NULL;
-
+  if (vis->class == PseudoColor)
+    {
+    
+      /* We request that the JPEG file be automatically quantized into
+	 8-bit color in case it's not already (many JPEGs are stored in
+	 24-bit color).  "Two-pass quantize" means that the colormap
+	 is determined on-the-fly for this particular image rather than
+	 quantizing to a supplied colormap.  We can get away with this
+	 because we then use allocate_nearest_color().
+
+	 #### Note of course that this is not the most color-effective
+	 way of doing things -- we could quantize an image that has
+	 lots of very similar colors, and eat up the colormap with these
+	 (useless to other images) colors.  Unfortunately I don't think
+	 there's any "general" way of maximizing the overall image
+	 quality of lots of images, given that we don't know the
+	 colors of the images until we come across each one.  Best we
+	 could do would be various sorts of heuristics, which I don't
+	 feel like dealing with now.  A better scheme would be the
+	 way things are done under MS Windows, where the colormap is
+	 dynamically adjusted for various applications; but that kind
+	 of thing would have to be provided by X, which it isn't. */
+      
+      cinfo.quantize_colors = TRUE;
+      cinfo.two_pass_quantize = TRUE;
+      cinfo.colormap = NULL;
+    }
+  
   /* Step 5: Start decompressor */
 
   jpeg_start_decompress (&cinfo);
@@ -2134,22 +2319,17 @@
   /* At this point we know the size of the image and the colormap. */
 
   /* Step 5.33: Allocate the colors */
-  {
+  if (vis->class == PseudoColor) {
     int i;
-
-    /* Just in case the image contains out-of-range pixels, we go
-       ahead and allocate space for all of them. */
-    unwind.pixels = xnew_array (unsigned long, 256);
-    unwind.npixels = cinfo.actual_number_of_colors;
-
-    for (i = 0; i < 256; i++)
-      unwind.pixels[i] = 0;   /* Use a reasonable color for out of range. */
+    unwind.pixcount = 32;
+    unwind.pixels = xnew_array (unsigned long, unwind.pixcount);
+    unwind.npixels = 0;
 
     /* Allocate pixels for the various colors. */
-    for (i = 0; i < unwind.npixels; i++)
+    for (i = 0; i < cinfo.actual_number_of_colors; i++)
       {
 	XColor color;
-	int ri, gi, bi;
+	int ri, gi, bi, res;
 
 	ri = 0;
 	gi = cinfo.out_color_components > 1 ? 1 : 0;
@@ -2163,8 +2343,13 @@
 	color.blue = cinfo.colormap[bi] ? cinfo.colormap[bi][i] << 8 : 0;
 	color.flags = DoRed | DoGreen | DoBlue;
 
-	allocate_nearest_color (dpy, cmap, vis, &color);
-	unwind.pixels[i] = color.pixel;
+	res = allocate_nearest_color (dpy, cmap, vis, &color);
+	if (res > 0 && res < 3)
+	  {
+	    DO_REALLOC(unwind.pixels, unwind.pixcount, unwind.npixels+1, unsigned long);
+	    unwind.pixels[unwind.npixels] = color.pixel;
+	    unwind.npixels++;
+	  }
       }
   }
 
@@ -2182,8 +2367,7 @@
 		  (depth >  8) ? 16 :
 		  8);
 
-    unwind.ximage = XCreateImage (dpy, DefaultVisualOfScreen (scr),
-				  depth, ZPixmap, 0, 0, width, height,
+    unwind.ximage = XCreateImage (dpy, vis, depth, ZPixmap, 0, 0, width, height,
 				  bitmap_pad, 0);
 
     if (!unwind.ximage)
@@ -2241,7 +2425,72 @@
 		     unwind.pixels[(unsigned char) row_buffer[0][i]]);
       }
   }
-
+#else
+  {
+    /* Step 4: set parameters for decompression.   */
+
+    /* Now that we're using EImages, use the default of all data in 24bit color.
+       The backend routine will take care of any necessary reductions. */
+
+    /* Step 5: Start decompressor */
+    jpeg_start_decompress (&cinfo);
+
+    /* Step 6: Read in the data and put into EImage format (8bit RGB triples)*/
+
+    unwind.eimage = (unsigned char*) xmalloc (cinfo.output_width * cinfo.output_height * 3);
+    if (!unwind.eimage)
+      signal_simple_error("Unable to allocate enough memory for image", instantiator);
+
+    {
+      JSAMPARRAY row_buffer;	/* Output row buffer */
+      JSAMPLE *jp;
+      int row_stride;		/* physical row width in output buffer */
+      unsigned char *op = unwind.eimage;
+
+      /* We may need to do some setup of our own at this point before reading
+       * the data.  After jpeg_start_decompress() we have the correct scaled
+       * output image dimensions available
+       * We need to make an output work buffer of the right size.
+       */
+      /* JSAMPLEs per row in output buffer. */
+      row_stride = cinfo.output_width * cinfo.output_components;
+      /* Make a one-row-high sample array that will go away when done
+	 with image */
+      row_buffer = ((*cinfo.mem->alloc_sarray)
+		    ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1));
+
+      /* Here we use the library's state variable cinfo.output_scanline as the
+       * loop counter, so that we don't have to keep track ourselves.
+       */
+      while (cinfo.output_scanline < cinfo.output_height)
+	{
+	  int i;
+
+	  /* jpeg_read_scanlines expects an array of pointers to scanlines.
+	   * Here the array is only one element long, but you could ask for
+	   * more than one scanline at a time if that's more convenient.
+	   */
+	  (void) jpeg_read_scanlines (&cinfo, row_buffer, 1);
+	  jp = row_buffer[0];
+	  for (i = 0; i < cinfo.output_width; i++) {
+	    int clr;
+#if (BITS_IN_JSAMPLE == 8)
+	    for (clr = 0; clr < 3; clr++)
+	      *op++ = (unsigned char)*jp++;
+#else /* other option is 12 */
+	    for (clr = 0; clr < 3; clr++)
+	      *op++ = (unsigned char)(*jp++ >> 4);
+#endif
+	  }
+	}
+      unwind.ximage = EImage2XImage (device, cinfo.output_width, cinfo.output_height, unwind.eimage,
+				     &unwind.pixels, &unwind.pixcount, &unwind.npixels);
+      if (!unwind.ximage)
+	signal_simple_error("JPEG conversion failed", instantiator);
+    }
+  }
+  
+#endif
   /* Step 6.5: Create the pixmap and set up the image instance */
   init_image_instance_from_x_image (ii, unwind.ximage, dest_mask,
 				    unwind.pixels, unwind.npixels,
@@ -2260,6 +2509,7 @@
      freed right now.  They're kept around in the image instance
      structure until it's destroyed. */
   unwind.npixels = 0;
+  unwind.pixcount = 0;
 
   /* This will clean up everything else. */
   unbind_to (speccount, Qnil);
@@ -2268,12 +2518,12 @@
 #endif /* HAVE_JPEG */
 
 #ifdef HAVE_GIF
-
+/* #define USE_TEMP_FILES_FOR_GIF_IMAGES */
 /**********************************************************************
  *                               GIF                                  *
  **********************************************************************/
 
-#include "gif_lib.h" /* This is in our own source tree */
+#include <gif_lib.h>
 
 static void
 gif_validate (Lisp_Object instantiator)
@@ -2301,16 +2551,19 @@
 {
   Display *dpy;
   Colormap cmap;
+  unsigned char *eimage;
   /* Object that holds the decoded data from a GIF file */
   GifFileType *giffile;
   /* Pixels to keep around while the image is active */
   unsigned long *pixels;
-  int npixels;
+  int npixels, pixcount;
   /* Client-side image structure */
   XImage *ximage;
+#ifdef USE_TEMP_FILES_FOR_GIF_IMAGES
   /* Tempfile to remove */
   char tempfile[50];
   int tempfile_needs_to_be_removed;
+#endif
 };
 
 static Lisp_Object
@@ -2321,14 +2574,19 @@
 
   free_opaque_ptr (unwind_obj);
   if (data->giffile)
-    DGifCloseFile (data->giffile);
+    {
+      DGifCloseFile (data->giffile);
+      GifFree(data->giffile);
+    }
+  if (data->eimage) xfree(data->eimage);
+#ifdef USE_TEMP_FILES_FOR_GIF_IMAGES
   if (data->tempfile_needs_to_be_removed)
     unlink (data->tempfile);
+#endif
   if (data->npixels > 0)
-    {
-      XFreeColors (data->dpy, data->cmap, data->pixels, data->npixels, 0L);
-      xfree (data->pixels);
-    }
+    XFreeColors (data->dpy, data->cmap, data->pixels, data->npixels, 0L);
+  if (data->pixcount > 0)
+    xfree (data->pixels);
   if (data->ximage)
     {
       if (data->ximage->data)
@@ -2342,6 +2600,46 @@
   return Qnil;
 }
 
+#ifndef USE_TEMP_FILES_FOR_GIF_IMAGES
+typedef struct gif_memory_storage
+{
+  Extbyte *bytes;		/* The data       */
+  Extcount len;			/* How big is it? */
+  int index;			/* Where are we?  */
+} gif_memory_storage;
+
+static size_t gif_read_from_memory(GifByteType *buf, size_t size, VoidPtr data)
+{
+  gif_memory_storage *mem = (gif_memory_storage*)data;
+
+  if (size > (mem->len - mem->index))
+    return -1;
+  memcpy(buf, mem->bytes + mem->index, size);
+  mem->index = mem->index + size;
+  return size;
+}
+
+static int gif_memory_close(VoidPtr data)
+{
+  return 0;
+}
+
+#endif
+struct gif_error_struct
+{
+  char *err_str;		/* return the error string */
+  jmp_buf setjmp_buffer;	/* for return to caller */
+};
+
+static void gif_error_func(CONST char *err_str, VoidPtr error_ptr)
+{
+  struct gif_error_struct *error_data = (struct gif_error_struct*)error_ptr;
+
+  /* return to setjmp point */
+  error_data->err_str = err_str;
+  longjmp (error_data->setjmp_buffer, 1);
+}
+
 static void
 gif_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
 		 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
@@ -2350,7 +2648,6 @@
   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
   Display *dpy;
-  Screen *scr;
   Colormap cmap;
   Visual *vis;
   /* It is OK for the unwind data to be local to this function,
@@ -2358,12 +2655,16 @@
      stack frame is still valid. */
   struct gif_unwind_data unwind;
   int speccount = specpdl_depth ();
-
+#ifndef USE_TEMP_FILES_FOR_GIF_IMAGES
+  gif_memory_storage mem_struct;
+  struct gif_error_struct gif_err;
+  Extbyte *bytes;
+  Extcount len;
+#endif
   if (!DEVICE_X_P (XDEVICE (device)))
     signal_simple_error ("Not an X device", device);
 
   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
-  scr = DefaultScreenOfDisplay (dpy);
   cmap = DEVICE_X_COLORMAP (XDEVICE(device));
   vis = DEVICE_X_VISUAL (XDEVICE(device));
 
@@ -2374,34 +2675,45 @@
 
   /* 1. Now decode the data. */
 
-  /* #### The GIF routines currently require that you read from a file,
-     so write out to a temp file.  We should change this. */
   {
     Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
 
     assert (!NILP (data));
 
+    if (!(unwind.giffile = GifSetup()))
+      signal_simple_error ("Insufficent memory to instantiate GIF image", instantiator);
+
+    /* set up error facilities */
+    if (setjmp(gif_err.setjmp_buffer)) {
+      /* An error was signaled. No clean up is needed, as unwind handles that
+	 for us.  Just pass the error along. */
+      Lisp_Object errstring;
+      errstring = build_string (gif_err.err_str);
+      signal_simple_error_2 ("GIF decoding error", errstring, instantiator);
+    }
+    GifSetErrorFunc(unwind.giffile, (Gif_error_func)gif_error_func, (VoidPtr)&gif_err);
+    
+#ifdef USE_TEMP_FILES_FOR_GIF_IMAGES
     write_lisp_string_to_temp_file (data, unwind.tempfile);
     unwind.tempfile_needs_to_be_removed = 1;
-
+    DGifOpenFileName (unwind.giffile, unwind.tempfile);
+#else
+    GET_STRING_BINARY_DATA_ALLOCA (data, bytes, len);
+    mem_struct.bytes = bytes;
+    mem_struct.len = len;
+    mem_struct.index = 0;
+    GifSetReadFunc(unwind.giffile, gif_read_from_memory, (VoidPtr)&mem_struct);
+    GifSetCloseFunc(unwind.giffile, gif_memory_close, (VoidPtr)&mem_struct);
+    DGifInitRead(unwind.giffile);
+#endif
     /* Then slurp the image into memory, decoding along the way.
        The result is the image in a simple one-byte-per-pixel
        format (#### the GIF routines only support 8-bit GIFs,
        it appears). */
-    unwind.giffile = DGifOpenFileName (unwind.tempfile);
-    if (unwind.giffile == NULL)
-      {
-      gif_decode_error:
-	signal_simple_error ("Unable to decode GIF",
-			     build_string (EmacsPrintGifError ()));
-      }
-    /* DGifSlurp() doesn't handle interlaced files. */
-    /* Actually, it does, sort of.  It just sets the Interlace flag
-       and stores RasterBits in interlaced order.  We handle that below. */
-    if (DGifSlurp (unwind.giffile) != GIF_OK)
-      goto gif_decode_error;
+    DGifSlurp (unwind.giffile);
   }
 
+#if 0
   /* 2. Now allocate the colors for the image. */
   {
     int i;
@@ -2409,7 +2721,7 @@
     /* Just in case the image contains out-of-range pixels, we go
        ahead and allocate space for all of them. */
     unwind.pixels = xnew_array (unsigned long, 256);
-    unwind.npixels = cmo->ColorCount;
+    unwind.npixels = 0;
 
     for (i = 0; i < 256; i++)
       unwind.pixels[i] = 0;   /* Use a reasonable color for out of range. */
@@ -2417,6 +2729,7 @@
     /* Allocate pixels for the various colors. */
     for (i = 0; i < cmo->ColorCount; i++)
       {
+	int res;
 	XColor color;
 
 	color.red = cmo->Colors[i].Red << 8;
@@ -2424,8 +2737,12 @@
 	color.blue = cmo->Colors[i].Blue << 8;
 	color.flags = DoRed | DoGreen | DoBlue;
 
-	allocate_nearest_color (dpy, cmap, vis, &color);
-	unwind.pixels[i] = color.pixel;
+	res = allocate_nearest_color (dpy, cmap, vis, &color);
+	if (res > 0 && res < 3)
+	  {
+	    unwind.pixels[unwind.npixels] = color.pixel;
+	    unwind.npixels++;
+	  }
       }
   }
 
@@ -2499,7 +2816,59 @@
 	row += interlace ? InterlacedJumps[pass] : 1;
       }
   }
-
+#else
+  /* 3. Now create the EImage */
+  {
+    ColorMapObject *cmo = unwind.giffile->SColorMap;
+    int height = unwind.giffile->SHeight;
+    int width = unwind.giffile->SWidth;
+    int i, j, row, pass, interlace;
+    unsigned char *eip;
+    /* interlaced gifs have rows in this order:
+       0, 8, 16, ..., 4, 12, 20, ..., 2, 6, 10, ..., 1, 3, 5, ...  */
+    static int InterlacedOffset[] = { 0, 4, 2, 1 };
+    static int InterlacedJumps[] = { 8, 8, 4, 2 };
+
+    unwind.eimage = (unsigned char*) xmalloc (width * height * 3);
+    if (!unwind.eimage)
+      signal_simple_error("Unable to allocate enough memory for image", instantiator);
+
+    /* write the data in EImage format (8bit RGB triples) */
+
+    /* Note: We just use the first image in the file and ignore the rest.
+             We check here that that image covers the full "screen" size.
+	     I don't know whether that's always the case.
+             -dkindred@cs.cmu.edu  */
+    if (unwind.giffile->SavedImages[0].ImageDesc.Height != height
+	|| unwind.giffile->SavedImages[0].ImageDesc.Width != width
+	|| unwind.giffile->SavedImages[0].ImageDesc.Left != 0
+	|| unwind.giffile->SavedImages[0].ImageDesc.Top != 0)
+      signal_simple_error ("First image in GIF file is not full size",
+			   instantiator);
+
+    interlace = unwind.giffile->SavedImages[0].ImageDesc.Interlace;
+    pass = 0;
+    row = interlace ? InterlacedOffset[pass] : 0;
+    eip = unwind.eimage;
+    for (i = 0; i < height; i++)
+      {
+	if (interlace && row >= height)
+	  row = InterlacedOffset[++pass];
+	eip = unwind.eimage + (row * width * 3);
+	for (j = 0; j < width; j++) {
+	  unsigned char pixel = unwind.giffile->SavedImages[0].RasterBits[(i * width) + j];
+	  *eip++ = cmo->Colors[pixel].Red;
+	  *eip++ = cmo->Colors[pixel].Green;
+	  *eip++ = cmo->Colors[pixel].Blue;
+	}
+	row += interlace ? InterlacedJumps[pass] : 1;
+      }
+    unwind.ximage = EImage2XImage (device, width, height, unwind.eimage,
+				   &unwind.pixels, &unwind.pixcount, &unwind.npixels);
+    if (!unwind.ximage)
+      signal_simple_error("GIF conversion failed", instantiator);
+  }
+#endif
   /* 4. Now create the pixmap and set up the image instance */
   init_image_instance_from_x_image (ii, unwind.ximage, dest_mask,
 				    unwind.pixels, unwind.npixels,
@@ -2508,6 +2877,7 @@
      freed right now.  They're kept around in the image instance
      structure until it's destroyed. */
   unwind.npixels = 0;
+  unwind.pixcount = 0;
   unbind_to (speccount, Qnil);
 }
 
@@ -2538,7 +2908,7 @@
   return IMAGE_COLOR_PIXMAP_MASK;
 }
 
-#if !defined (USE_TEMP_FILES_FOR_PNG_IMAGES) && (PNG_LIBPNG_VER >= 87)
+#ifndef USE_TEMP_FILES_FOR_PNG_IMAGES
 struct png_memory_storage
 {
   Extbyte *bytes;		/* The data       */
@@ -2547,7 +2917,7 @@
 };
 
 static void png_read_from_memory(png_structp png_ptr, png_bytep data,
-				 png_uint_32 length)
+				 png_size_t length)
 {
    struct png_memory_storage *tbr =
      (struct png_memory_storage *) png_get_io_ptr (png_ptr);
@@ -2557,20 +2927,48 @@
    memcpy(data,tbr->bytes + tbr->index,length);
    tbr->index = tbr->index + length;
 }
-#endif /* !USE_TEMP_FILES_FOR_PNG_IMAGESS || PNG_LIBPNG_VER >= 87 */
+#endif /* !USE_TEMP_FILES_FOR_PNG_IMAGES */
+
+struct png_error_struct
+{
+  CONST char *err_str;
+  jmp_buf setjmp_buffer;	/* for return to caller */
+};
+
+/* jh 98/03/12 - #### AARRRGH! libpng includes jmp_buf inside its own
+   structure, and there are cases where the size can be different from
+   between inside the libarary, and inside the code!  To do an end run
+   around this, use our own error functions, and don't rely on things
+   passed in the png_ptr to them.  This is an ugly hack and must
+   go away when the lisp engine is threaded! */
+static struct png_error_struct png_err_stct;
+
+static void png_error_func(png_structp png_ptr, png_const_charp message)
+{
+  png_err_stct.err_str = message;
+  longjmp (png_err_stct.setjmp_buffer, 1);
+}
+
+static void png_warning_func(png_structp png_ptr, png_const_charp message)
+{
+  warn_when_safe (Qpng, Qinfo, "%s", message);
+}
 
 struct png_unwind_data
 {
   Display *dpy;
   Colormap cmap;
   FILE *instream;
-  png_struct *png_ptr;
-  png_info *info_ptr;
+  unsigned char *eimage;
+  png_structp png_ptr;
+  png_infop info_ptr;
   unsigned long *pixels;
-  int npixels;
+  int npixels, pixcount;
   XImage *ximage;
+#ifdef USE_TEMP_FILES_FOR_PNG_IMAGESS
   char tempfile[50];
   int tempfile_needs_to_be_removed;
+#endif
 };
 
 static Lisp_Object
@@ -2581,17 +2979,16 @@
 
   free_opaque_ptr (unwind_obj);
   if (data->png_ptr)
-    png_read_destroy (data->png_ptr, data->info_ptr, (png_info *) NULL);
+    png_destroy_read_struct (&(data->png_ptr), &(data->info_ptr), (png_infopp)NULL);
   if (data->instream)
     fclose (data->instream);
-  if (data->tempfile_needs_to_be_removed)
-    unlink (data->tempfile);
   if (data->npixels > 0)
-    {
-      XFreeColors (data->dpy, data->cmap, data->pixels, data->npixels, 0L);
-      xfree (data->pixels);
-    }
-
+    XFreeColors (data->dpy, data->cmap, data->pixels, data->npixels, 0L);
+  if (data->pixcount > 0)
+    xfree (data->pixels);
+
+  if (data->eimage)
+    xfree (data->eimage);
   if (data->ximage)
     {
       if (data->ximage->data)
@@ -2601,27 +2998,13 @@
 	}
       XDestroyImage (data->ximage);
     }
-
+#ifdef USE_TEMP_FILES_FOR_PNG_IMAGES
+  if (data->tempfile_needs_to_be_removed)
+    unlink (data->tempfile);
+#endif
   return Qnil;
 }
 
-/* This doesn't appear to be used. */
-#if 0
-#define get_png_val(p) _get_png_val (&(p), info_ptr.bit_depth)
-png_uint_16
-_get_png_val (png_byte **pp, int bit_depth)
-{
-  png_uint_16 c = 0;
-
-  if (bit_depth == 16) {
-    c = (*((*pp)++)) << 8;
-  }
-  c |= (*((*pp)++));
-
-  return c;
-}
-#endif
-
 static void
 png_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
 		 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
@@ -2636,8 +3019,8 @@
   int speccount = specpdl_depth ();
 
   /* PNG variables */
-  png_struct *png_ptr;
-  png_info *info_ptr;
+  png_structp png_ptr;
+  png_infop info_ptr;
 
   if (!DEVICE_X_P (XDEVICE (device)))
     signal_simple_error ("Not an X device", device);
@@ -2646,9 +3029,18 @@
   cmap = DEVICE_X_COLORMAP (XDEVICE(device));
   vis = DEVICE_X_VISUAL (XDEVICE(device));
 
-  png_ptr  = xnew (png_struct);
-  info_ptr = xnew (png_info);
-
+  /* Initialize all PNG structures */
+  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (void*)&png_err_stct,
+				   png_error_func, png_warning_func);
+  if (!png_ptr)
+    signal_simple_error("Error obtaining memory for png_read", instantiator);
+  info_ptr = png_create_info_struct(png_ptr);
+  if (!info_ptr)
+    {
+      png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+      signal_simple_error("Error obtaining memory for png_read", instantiator);
+    }
+  
   memset (&unwind, 0, sizeof (unwind));
   unwind.png_ptr = png_ptr;
   unwind.info_ptr = info_ptr;
@@ -2661,45 +3053,21 @@
      this file, example.c from the libpng 0.81 distribution, and the
      pngtopnm sources. -WMP-
      */
-#if defined (USE_TEMP_FILES_FOR_PNG_IMAGES) || (PNG_LIBPNG_VER < 87)
-  /* Write out to a temp file - we really should take the time to
-     write appropriate memory bound IO stuff, but I am just trying
-     to get the stupid thing working right now.
-     */
-  {
-    Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
-
-    assert (!NILP (data));
-
-    write_lisp_string_to_temp_file (data, unwind.tempfile);
-    unwind.tempfile_needs_to_be_removed = 1;
-
-    if ((unwind.instream = fopen (unwind.tempfile, "rb")) == NULL)
-      report_file_error ("Opening PNG temp file",
-			 list1 (build_string (unwind.tempfile)));
-  }
-#else
-  /* Nothing */
-#endif
+  /* It has been further modified to handle the API changes for 0.96,
+     and is no longer usable for previous versions. jh
+  */
 
   /* Set the jmp_buf reurn context for png_error ... if this returns !0, then
      we ran into a problem somewhere, and need to clean up after ourselves. */
-  if (setjmp (png_ptr->jmpbuf))
+  if (setjmp (png_err_stct.setjmp_buffer))
     {
-      /* Am I doing enough here?  I think so, since most things happen
-         in png_unwind */
-      png_read_destroy (png_ptr, info_ptr, (png_info *) NULL);
-      signal_simple_error ("Error decoding PNG", instantiator);
+      /* Something blew up: just display the error (cleanup happens in the unwind) */
+      signal_simple_error_2 ("Error decoding PNG",
+			     build_string(png_err_stct.err_str),
+			     instantiator);
     }
 
-  /* Initialize all PNG structures */
-  png_info_init (info_ptr);
-  png_read_init (png_ptr);
-
   /* Initialize the IO layer and read in header information */
-#if defined (USE_TEMP_FILES_FOR_PNG_IMAGES) || (PNG_LIBPNG_VER < 87)
-  png_init_io (png_ptr, unwind.instream);
-#else
   {
     Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
     Extbyte *bytes;
@@ -2709,18 +3077,17 @@
     assert (!NILP (data));
 
     /* #### This is a definite problem under Mule due to the amount of
-       stack data it might allocate.  Need to be able to convert and
-       write out to a file. */
+       stack data it might allocate.  Need to think about using Lstreams */
     GET_STRING_BINARY_DATA_ALLOCA (data, bytes, len);
     tbr.bytes = bytes;
     tbr.len = len;
     tbr.index = 0;
     png_set_read_fn(png_ptr,(void *) &tbr, png_read_from_memory);
   }
-#endif
 
   png_read_info (png_ptr, info_ptr);
 
+#if 0
   /* set up the transformations you want.  Note that these are
      all optional.  Only call them if you want them */
   /* tell libpng to strip 16 bit depth files down to 8 bits */
@@ -2743,12 +3110,11 @@
     png_color static_color_cube[216];
 
     /* Wow, allocate all the memory.  Truly, exciting. */
-    unwind.pixels = xnew_array (unsigned long, 256);
+    unwind.pixcount = 32;
+    unwind.pixels = xnew_array (unsigned long, unwind.pixcount);
     png_pixels    = xnew_array (png_byte, linesize * height);
     row_pointers  = xnew_array (png_byte *, height);
 
-    for (y = 0; y < 256; y++)
-      unwind.pixels[y] = 0;
     for (y = 0; y < height; y++)
       row_pointers[y] = png_pixels + (linesize * y);
 
@@ -2770,8 +3136,9 @@
     }
 #endif
 
-    if ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
-	(info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA))
+    if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+	 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
+	(vis->class == PseudoColor))
       {
 	if (!(info_ptr->valid & PNG_INFO_PLTE))
 	  {
@@ -2796,28 +3163,39 @@
     /* Ok, now we go and allocate all the colors */
     if (info_ptr->valid & PNG_INFO_PLTE)
       {
-	unwind.npixels = info_ptr->num_palette;
-	for (y = 0; y < unwind.npixels; y++)
+	unwind.npixels = 0;
+	for (y = 0; y < info_ptr->num_palette; y++)
 	  {
+	    int res;
 	    color.red = info_ptr->palette[y].red << 8;
 	    color.green = info_ptr->palette[y].green << 8;
 	    color.blue = info_ptr->palette[y].blue << 8;
 	    color.flags = DoRed | DoGreen | DoBlue;
-	    allocate_nearest_color (dpy, cmap, vis, &color);
-	    unwind.pixels[y] = color.pixel;
+	    res = allocate_nearest_color (dpy, cmap, vis, &color);
+	    if (res > 0 && res < 3)
+	      {
+		DO_REALLOC(unwind.pixels, unwind.pixcount, unwind.npixels+1, unsigned long);
+		unwind.pixels[unwind.npixels] = color.pixel;
+		unwind.npixels++;
+	      }
 	  }
       }
     else
       {
-	unwind.npixels = 216;
+	unwind.npixels = 0;
 	for (y = 0; y < 216; y++)
 	  {
+	    int res;
 	    color.red = static_color_cube[y].red << 8;
 	    color.green = static_color_cube[y].green << 8;
 	    color.blue = static_color_cube[y].blue << 8;
 	    color.flags = DoRed|DoGreen|DoBlue;
-	    allocate_nearest_color (dpy, cmap, vis, &color);
-	    unwind.pixels[y] = color.pixel;
+	    res = allocate_nearest_color (dpy, cmap, vis, &color);
+	    if (res > 0 && res < 3)
+	      {
+		unwind.pixels[unwind.npixels] = color.pixel;
+		unwind.npixels++;
+	      }
 	  }
       }
 
@@ -2877,6 +3255,105 @@
     xfree (row_pointers);
     xfree (png_pixels);
   }
+#else
+  {
+    int height = info_ptr->height;
+    int width = info_ptr->width;
+    int y;
+    unsigned char **row_pointers;
+
+    /* Wow, allocate all the memory.  Truly, exciting. */
+    unwind.eimage = xnew_array_and_zero (unsigned char, width * height * 3);
+    /* libpng expects that the image buffer passed in contains a
+       picture to draw on top of if the png has any transparencies.
+       This could be a good place to pass that in... */
+    
+    row_pointers  = xnew_array (png_byte *, height);
+
+    for (y = 0; y < height; y++)
+      row_pointers[y] = unwind.eimage + (width * 3 * y);
+
+    /* Now that we're using EImage, ask for 8bit RGB triples for any type
+       of image*/
+    /* convert palatte images to full RGB */
+    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+      png_set_expand(png_ptr);
+    /* send grayscale images to RGB too */
+    if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
+        info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+      png_set_gray_to_rgb(png_ptr);
+    /* we can't handle alpha values */
+    if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+      png_set_strip_alpha(png_ptr);
+    /* rip out any transparancy layers/colors */
+    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+        png_set_expand(png_ptr);
+	png_set_strip_alpha(png_ptr);
+    }
+    /* tell libpng to strip 16 bit depth files down to 8 bits */
+    if (info_ptr->bit_depth == 16)
+      png_set_strip_16 (png_ptr);
+    /* if the image is < 8 bits, pad it out */
+    if (info_ptr->bit_depth < 8) {
+      if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+	png_set_expand(png_ptr);
+      else
+	png_set_packing (png_ptr);
+    }
+
+#if 1 /* tests? or permanent? */
+    {
+      /* if the png specifies a background chunk, go ahead and
+	 use it */
+      png_color_16 my_background, *image_background;
+    
+      /* ### how do I get the background of the current frame? */
+      my_background.red = 0x7fff;
+      my_background.green = 0x7fff;
+      my_background.blue = 0x7fff;
+
+      if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+	png_set_background(png_ptr, image_background,
+			   PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+      else 
+	png_set_background(png_ptr, &my_background,
+			   PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+    }
+#endif
+    png_read_image (png_ptr, row_pointers);
+    png_read_end (png_ptr, info_ptr);
+    
+#ifdef PNG_SHOW_COMMENTS
+    /* ####
+     * I turn this off by default now, because the !%^@#!% comments
+     * show up every time the image is instantiated, which can get
+     * really really annoying.  There should be some way to pass this
+     * type of data down into the glyph code, where you can get to it
+     * from lisp anyway. - WMP
+     */
+    {
+      int i;
+
+      for (i = 0 ; i < info_ptr->num_text ; i++)
+	{
+	  /* How paranoid do I have to be about no trailing NULLs, and
+	     using (int)info_ptr->text[i].text_length, and strncpy and a temp
+	     string somewhere? */
+
+	  warn_when_safe (Qpng, Qinfo, "%s - %s",
+			  info_ptr->text[i].key,
+			  info_ptr->text[i].text);
+	}
+    }
+#endif
+
+    xfree (row_pointers);
+    unwind.ximage = EImage2XImage (device, width, height, unwind.eimage,
+				   &unwind.pixels, &unwind.pixcount, &unwind.npixels);
+    if (!unwind.ximage)
+      signal_simple_error("PNG conversion failed", instantiator);
+  }
+#endif
 
   init_image_instance_from_x_image (ii, unwind.ximage, dest_mask,
 				    unwind.pixels, unwind.npixels,
@@ -2884,6 +3361,7 @@
 
   /* This will clean up everything else. */
   unwind.npixels = 0;
+  unwind.pixcount = 0;
   unbind_to (speccount, Qnil);
 }
 
@@ -2891,6 +3369,7 @@
 
 
 #ifdef HAVE_TIFF
+#include "tiffio.h"
 
 /**********************************************************************
  *                             TIFF                                   *
@@ -2904,8 +3383,7 @@
 static Lisp_Object
 tiff_normalize (Lisp_Object inst, Lisp_Object console_type)
 {
-  signal_simple_error ("No TIFF support yet", inst);
-  return Qnil;
+  return simple_image_type_normalize (inst, console_type, Qtiff);
 }
 
 static int
@@ -2914,12 +3392,280 @@
   return IMAGE_COLOR_PIXMAP_MASK;
 }
 
+struct tiff_unwind_data
+{
+  Display *dpy;
+  Colormap cmap;
+  unsigned char *eimage;
+  /* Object that holds the decoded data from a TIFF file */
+  TIFF *tiff;
+  /* Pixels to keep around while the image is active */
+  unsigned long *pixels;
+  int npixels,pixcount;
+  /* Client-side image structure */
+  XImage *ximage;
+};
+
+static Lisp_Object
+tiff_instantiate_unwind (Lisp_Object unwind_obj)
+{
+  struct tiff_unwind_data *data =
+    (struct tiff_unwind_data *) get_opaque_ptr (unwind_obj);
+
+  free_opaque_ptr (unwind_obj);
+  if (data->tiff)
+    {
+      TIFFClose(data->tiff);
+    }
+  if (data->eimage)
+    xfree(data->eimage);
+  if (data->npixels > 0)
+    XFreeColors (data->dpy, data->cmap, data->pixels, data->npixels, 0L);
+  if (data->pixcount)
+    xfree (data->pixels);
+  if (data->ximage)
+    {
+      if (data->ximage->data)
+        {
+	  xfree (data->ximage->data);
+          data->ximage->data = 0;
+        }
+      XDestroyImage (data->ximage);
+    }
+
+  return Qnil;
+}
+
+typedef struct tiff_memory_storage
+{
+  Extbyte *bytes;		/* The data       */
+  Extcount len;			/* How big is it? */
+  int index;			/* Where are we?  */
+} tiff_memory_storage;
+
+static size_t tiff_memory_read(thandle_t data, tdata_t buf, tsize_t size)
+{
+  tiff_memory_storage *mem = (tiff_memory_storage*)data;
+
+  if (size > (mem->len - mem->index))
+    return -1;
+  memcpy(buf, mem->bytes + mem->index, size);
+  mem->index = mem->index + size;
+  return size;
+}
+
+static size_t tiff_memory_write(thandle_t data, tdata_t buf, tsize_t size)
+{
+  abort();
+}
+
+static toff_t tiff_memory_seek(thandle_t data, toff_t off, int whence)
+{
+  tiff_memory_storage *mem = (tiff_memory_storage*)data;
+  int newidx;
+  switch(whence) {
+  case SEEK_SET:
+    newidx = off;
+    break;
+  case SEEK_END:
+    newidx = mem->len + off;
+    break;
+  case SEEK_CUR:
+    newidx = mem->index + off;
+    break;
+  default:
+    fprintf(stderr,"Eh? invalid seek mode in tiff_memory_seek\n");
+    return -1;
+  }
+
+  if ((newidx > mem->len) || (newidx < 0))
+    return -1;
+  
+  mem->index = newidx;
+  return newidx;
+}
+
+static int tiff_memory_close(thandle_t data)
+{
+  return 0;
+}
+
+static int tiff_map_noop(thandle_t data, tdata_t* pbase, toff_t* psize)
+{
+  return 0;
+}
+
+static void tiff_unmap_noop(thandle_t data, tdata_t pbase, toff_t psize)
+{
+  return;
+}
+
+static toff_t tiff_memory_size(thandle_t data)
+{
+  tiff_memory_storage *mem = (tiff_memory_storage*)data;
+  return mem->len;
+}
+
+struct tiff_error_struct
+{
+#if HAVE_VSNPRINTF
+  char err_str[256];
+#else
+  char err_str[1024];		/* return the error string */
+#endif
+  jmp_buf setjmp_buffer;	/* for return to caller */
+};
+
+/* jh 98/03/12 - ###This struct for passing data to the error functions
+   is an ugly hack caused by the fact that libtiff (as of v3.4) doesn't
+   have any place to store error func data.  This should be rectified
+   before XEmacs gets threads! */
+static struct tiff_error_struct tiff_err_data;
+
+static void tiff_error_func(CONST char *module, CONST char *fmt, ...)
+{
+  va_list vargs;
+
+  va_start (vargs, fmt);
+#if HAVE_VSNPRINTF
+  vsnprintf(tiff_err_data.err_str, 255, fmt, vargs);
+#else
+  /* pray this doesn't overflow... */
+  vsprintf(tiff_err_data.err_str, fmt, vargs);
+#endif
+  va_end(vargs);
+  /* return to setjmp point */
+  longjmp (tiff_err_data.setjmp_buffer, 1);
+}
+
+static void tiff_warning_func(CONST char *module, CONST char *fmt, ...)
+{
+  va_list vargs;
+#if HAVE_VSNPRINTF
+  char warn_str[256];
+#else
+  char warn_str[1024];
+#endif
+
+  va_start (vargs, fmt);
+#if HAVE_VSNPRINTF
+  vsnprintf(warn_str, 255, fmt, vargs);
+#else
+  vsprintf(warn_str, fmt, vargs);
+#endif
+  va_end(vargs);
+  warn_when_safe (Qtiff, Qinfo, "%s - %s",
+		  module, warn_str);
+}
+
 static void
 tiff_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
 		  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
 		  int dest_mask, Lisp_Object domain)
 {
-  abort ();
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  Colormap cmap;
+  Display *dpy;
+  tiff_memory_storage mem_struct;
+  /* It is OK for the unwind data to be local to this function,
+     because the unwind-protect is always executed when this
+     stack frame is still valid. */
+  struct tiff_unwind_data unwind;
+  int speccount = specpdl_depth ();
+
+  if (!DEVICE_X_P (XDEVICE (device)))
+    signal_simple_error ("Not an X device", device);
+
+  dpy = DEVICE_X_DISPLAY (XDEVICE (device));
+  cmap = DEVICE_X_COLORMAP (XDEVICE(device));
+
+  memset (&unwind, 0, sizeof (unwind));
+  unwind.dpy = dpy;
+  unwind.cmap = cmap;
+  record_unwind_protect (tiff_instantiate_unwind, make_opaque_ptr (&unwind));
+  
+  /* set up error facilities */
+  if (setjmp(tiff_err_data.setjmp_buffer)) {
+    /* An error was signaled. No clean up is needed, as unwind handles that
+       for us.  Just pass the error along. */
+    Lisp_Object errstring;
+    errstring = build_string (tiff_err_data.err_str);
+    signal_simple_error_2 ("TIFF decoding error", errstring, instantiator);
+  }
+  TIFFSetErrorHandler((TIFFErrorHandler)tiff_error_func);
+  TIFFSetWarningHandler((TIFFErrorHandler)tiff_warning_func);
+  {
+    Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
+    Extbyte *bytes;
+    Extcount len;
+
+    uint32 width, height;
+    uint32 *raster;
+    unsigned char *ep;
+
+    assert (!NILP (data));
+
+    /* #### This is a definite problem under Mule due to the amount of
+       stack data it might allocate.  Think about Lstreams... */
+    GET_STRING_BINARY_DATA_ALLOCA (data, bytes, len);
+    mem_struct.bytes = bytes;
+    mem_struct.len = len;
+    mem_struct.index = 0;
+
+    unwind.tiff = TIFFClientOpen("memfile", "r", &mem_struct,
+				 (TIFFReadWriteProc)tiff_memory_read,
+				 (TIFFReadWriteProc)tiff_memory_write,
+				 tiff_memory_seek, tiff_memory_close, tiff_memory_size,
+				 tiff_map_noop, tiff_unmap_noop);
+    if (!unwind.tiff)
+      signal_simple_error ("Insufficent memory to instantiate TIFF image", instantiator);
+
+    TIFFGetField(unwind.tiff, TIFFTAG_IMAGEWIDTH, &width);
+    TIFFGetField(unwind.tiff, TIFFTAG_IMAGELENGTH, &height);
+    unwind.eimage = xmalloc(width * height * 3);
+
+    /* ### This is little more than proof-of-concept/function testing.
+       It needs to be reimplimented via scanline reads for both memory
+       compactness. */
+    raster = (uint32*) _TIFFmalloc(width * height * sizeof (uint32));
+    if (raster != NULL) {
+  int i,j;
+      uint32 *rp;
+      ep = unwind.eimage;
+      rp = raster;
+      if (TIFFReadRGBAImage(unwind.tiff, width, height, raster, 0)) {
+	for (i = height - 1;  i >= 0; i--) {
+	  /* This is to get around weirdness in the libtiff library where properly
+	     made TIFFs will come out upside down.  libtiff bug or jhod-brainlock? */
+	  rp = raster + (i * width);
+	  for (j = 0; j < width; j++) {
+	    *ep++ = (unsigned char)TIFFGetR(*rp);
+	    *ep++ = (unsigned char)TIFFGetG(*rp);
+	    *ep++ = (unsigned char)TIFFGetB(*rp);
+	    rp++;
+	  }
+	}
+      }
+      _TIFFfree(raster);
+    } else
+      signal_simple_error ("Unable to allocate memory for TIFFReadRGBA", instantiator);
+
+    unwind.ximage = EImage2XImage (device, width, height, unwind.eimage,
+				   &unwind.pixels, &unwind.pixcount, &unwind.npixels);
+    if (!unwind.ximage)
+      signal_simple_error("TIFF conversion failed", instantiator);    
+  }
+  /* Now create the pixmap and set up the image instance */
+  init_image_instance_from_x_image (ii, unwind.ximage, dest_mask,
+				    unwind.pixels, unwind.npixels,
+				    instantiator);
+  /* Now that we've succeeded, we don't want the pixels
+     freed right now.  They're kept around in the image instance
+     structure until it's destroyed. */
+  unwind.npixels = 0;
+  unwind.pixcount = 0;
+  unbind_to (speccount, Qnil);
 }
 
 #endif /* HAVE_TIFF */