]> git.imager.perl.org - imager.git/blobdiff - tiff.c
quote the use of min in type=>min, and at least give it some basic
[imager.git] / tiff.c
diff --git a/tiff.c b/tiff.c
index 1485a199c5a3cfa0c2931b25b7f3b2033d9e6467..317c599ea5d74d0ab08b04806b244a0cecafc295 100644 (file)
--- a/tiff.c
+++ b/tiff.c
@@ -67,6 +67,12 @@ static void expand_4bit_hl(unsigned char *buf, int count);
 
 static void pack_4bit_hl(unsigned char *buf, int count);
 
+
+static toff_t sizeproc(thandle_t x) {
+       return 0;
+}
+
+
 /*
 =item comp_seek(h, o, w)
 
@@ -86,26 +92,12 @@ comp_seek(thandle_t h, toff_t o, int w) {
   return (toff_t) ig->seekcb(ig, o, w);
 }
 
-
-/*
-=item i_readtiff_wiol(ig, length)
-
-Retrieve an image and stores in the iolayer object. Returns NULL on fatal error.
-
-   ig     - io_glue object
-   length - maximum length to read from data source, before closing it
-
-=cut
-*/
-
-i_img*
-i_readtiff_wiol(io_glue *ig, int length) {
+static i_img *read_one_tiff(TIFF *tif) {
   i_img *im;
   uint32 width, height;
   uint16 channels;
   uint32* raster = NULL;
   int tiled, error;
-  TIFF* tif;
   float xres, yres;
   uint16 resunit;
   int gotXres, gotYres;
@@ -113,37 +105,9 @@ i_readtiff_wiol(io_glue *ig, int length) {
   uint16 bits_per_sample;
   int i;
   int ch;
-  TIFFErrorHandler old_handler;
-
-  i_clear_error();
-  old_handler = TIFFSetErrorHandler(error_handler);
 
   error = 0;
 
-  /* Add code to get the filename info from the iolayer */
-  /* Also add code to check for mmapped code */
-
-  io_glue_commit_types(ig);
-  mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
-  
-  tif = TIFFClientOpen("(Iolayer)", 
-                      "rm", 
-                      (thandle_t) ig,
-                      (TIFFReadWriteProc) ig->readcb,
-                      (TIFFReadWriteProc) ig->writecb,
-                      (TIFFSeekProc) comp_seek,
-                      (TIFFCloseProc) ig->closecb,
-                      (TIFFSizeProc) ig->sizecb,
-                      (TIFFMapFileProc) NULL,
-                      (TIFFUnmapFileProc) NULL);
-  
-  if (!tif) {
-    mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
-    i_push_error(0, "opening file");
-    TIFFSetErrorHandler(old_handler);
-    return NULL;
-  }
-
   TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
   TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
   TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &channels);
@@ -207,17 +171,13 @@ i_readtiff_wiol(io_glue *ig, int length) {
 
     if (!TIFFGetField(tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2)) {
       i_push_error(0, "Cannot get colormap for paletted image");
-      TIFFSetErrorHandler(old_handler);
       i_img_destroy(im);
-      TIFFClose(tif);
       return NULL;
     }
     buffer = (unsigned char *)_TIFFmalloc(width+2);
     if (!buffer) {
       i_push_error(0, "out of memory");
-      TIFFSetErrorHandler(old_handler);
       i_img_destroy(im);
-      TIFFClose(tif);
       return NULL;
     }
     row = 0;
@@ -270,8 +230,6 @@ i_readtiff_wiol(io_glue *ig, int length) {
       if (!raster) {
         i_img_destroy(im);
         i_push_error(0, "No space for raster buffer");
-        TIFFSetErrorHandler(old_handler);
-        TIFFClose(tif);
         return NULL;
       }
       
@@ -309,8 +267,6 @@ i_readtiff_wiol(io_glue *ig, int length) {
       if (!raster) {
         i_img_destroy(im);
         i_push_error(0, "No space for raster buffer");
-        TIFFSetErrorHandler(old_handler);
-        TIFFClose(tif);
         return NULL;
       }
       
@@ -346,29 +302,227 @@ i_readtiff_wiol(io_glue *ig, int length) {
   }
   if (raster)
     _TIFFfree( raster );
+
+  return im;
+}
+
+/*
+=item i_readtiff_wiol(im, ig)
+
+=cut
+*/
+i_img*
+i_readtiff_wiol(io_glue *ig, int length) {
+  TIFF* tif;
+  TIFFErrorHandler old_handler;
+  i_img *im;
+
+  i_clear_error();
+  old_handler = TIFFSetErrorHandler(error_handler);
+
+  /* Add code to get the filename info from the iolayer */
+  /* Also add code to check for mmapped code */
+
+  io_glue_commit_types(ig);
+  mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
+  
+  tif = TIFFClientOpen("(Iolayer)", 
+                      "rm", 
+                      (thandle_t) ig,
+                      (TIFFReadWriteProc) ig->readcb,
+                      (TIFFReadWriteProc) ig->writecb,
+                      (TIFFSeekProc) comp_seek,
+                      (TIFFCloseProc) ig->closecb,
+                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+                      (TIFFMapFileProc) NULL,
+                      (TIFFUnmapFileProc) NULL);
+  
+  if (!tif) {
+    mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
+    i_push_error(0, "opening file");
+    TIFFSetErrorHandler(old_handler);
+    return NULL;
+  }
+
+  im = read_one_tiff(tif);
+
   if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
   TIFFSetErrorHandler(old_handler);
   TIFFClose(tif);
   return im;
 }
 
+/*
+=item i_readtiff_multi_wiol(ig, length, *count)
 
+Reads multiple images from a TIFF.
 
-/*
-=item i_writetif_wiol(im, ig)
+=cut
+*/
+i_img**
+i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
+  TIFF* tif;
+  TIFFErrorHandler old_handler;
+  i_img **results = NULL;
+  int result_alloc = 0;
+  int dirnum = 0;
 
-Stores an image in the iolayer object.
+  i_clear_error();
+  old_handler = TIFFSetErrorHandler(error_handler);
 
-   im - image object to write out
-   ig - io_object that defines source to write to 
+  /* Add code to get the filename info from the iolayer */
+  /* Also add code to check for mmapped code */
 
-=cut 
-*/
+  io_glue_commit_types(ig);
+  mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
+  
+  tif = TIFFClientOpen("(Iolayer)", 
+                      "rm", 
+                      (thandle_t) ig,
+                      (TIFFReadWriteProc) ig->readcb,
+                      (TIFFReadWriteProc) ig->writecb,
+                      (TIFFSeekProc) comp_seek,
+                      (TIFFCloseProc) ig->closecb,
+                      (TIFFSizeProc) ig->sizecb,
+                      (TIFFMapFileProc) NULL,
+                      (TIFFUnmapFileProc) NULL);
+  
+  if (!tif) {
+    mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
+    i_push_error(0, "opening file");
+    TIFFSetErrorHandler(old_handler);
+    return NULL;
+  }
 
-/* FIXME: Add an options array in here soonish */
+  *count = 0;
+  do {
+    i_img *im = read_one_tiff(tif);
+    if (!im)
+      break;
+    if (++*count > result_alloc) {
+      if (result_alloc == 0) {
+        result_alloc = 5;
+        results = mymalloc(result_alloc * sizeof(i_img *));
+      }
+      else {
+        i_img **newresults;
+        result_alloc *= 2;
+        newresults = myrealloc(results, result_alloc * sizeof(i_img *));
+      }
+    }
+    results[*count-1] = im;
+  } while (TIFFSetDirectory(tif, ++dirnum));
+
+  TIFFSetErrorHandler(old_handler);
+  TIFFClose(tif);
+  return results;
+}
 
 undef_int
-i_writetiff_wiol(i_img *im, io_glue *ig) {
+i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
+  uint32 width, height;
+  unsigned char *linebuf = NULL;
+  uint32 y;
+  int rc;
+  uint32 x;
+  int luma_mask;
+  uint32 rowsperstrip;
+  float vres = fine ? 196 : 98;
+  int luma_chan;
+
+  width    = im->xsize;
+  height   = im->ysize;
+
+  switch (im->channels) {
+  case 1:
+  case 2:
+    luma_chan = 0;
+    break;
+  case 3:
+  case 4:
+    luma_chan = 1;
+    break;
+  default:
+    /* This means a colorspace we don't handle yet */
+    mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
+    return 0;
+  }
+
+  /* Add code to get the filename info from the iolayer */
+  /* Also add code to check for mmapped code */
+
+
+  mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
+  
+  if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   )
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  )
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT))
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   1)        )
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
+
+  linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
+  
+  if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
+    mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
+
+  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
+
+  mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
+  mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
+  mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
+
+  if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
+    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
+  if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
+    mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0; 
+  }
+
+  if (!save_tiff_tags(tif, im)) {
+    return 0;
+  }
+
+  for (y=0; y<height; y++) {
+    int linebufpos=0;
+    for(x=0; x<width; x+=8) { 
+      int bits;
+      int bitpos;
+      i_sample_t luma[8];
+      uint8 bitval = 128;
+      linebuf[linebufpos]=0;
+      bits = width-x; if(bits>8) bits=8;
+      i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
+      for(bitpos=0;bitpos<bits;bitpos++) {
+       linebuf[linebufpos] |= ((luma[bitpos]>=128)?bitval:0);
+       bitval >>= 1;
+      }
+      linebufpos++;
+    }
+    if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
+      mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
+      break;
+    }
+  }
+  if (linebuf) _TIFFfree(linebuf);
+
+  return 1;
+}
+
+undef_int
+i_writetiff_low(TIFF *tif, i_img *im) {
   uint32 width, height;
   uint16 channels;
   uint16 predictor = 0;
@@ -383,17 +537,12 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
   tsize_t linebytes;
   int ch, ci, rc;
   uint32 x;
-  TIFF* tif;
   int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
   double xres, yres;
   uint16 bitspersample = 8;
   uint16 samplesperpixel;
   uint16 *colors = NULL;
 
-  char *cc = mymalloc( 123 );
-  myfree(cc);
-
-
   width    = im->xsize;
   height   = im->ysize;
   channels = im->channels;
@@ -418,37 +567,35 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
   /* Add code to get the filename info from the iolayer */
   /* Also add code to check for mmapped code */
 
-  io_glue_commit_types(ig);
-  mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));
+  /*io_glue_commit_types(ig);*/
+  /*mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));*/
 
-  /* FIXME: Enable the mmap interface */
+  mm_log((1, "i_writetiff_low: width=%d, height=%d, channels=%d\n", width, height, channels));
   
-  tif = TIFFClientOpen("No name", 
-                      "wm",
-                      (thandle_t) ig, 
-                      (TIFFReadWriteProc) ig->readcb,
-                      (TIFFReadWriteProc) ig->writecb,
-                      (TIFFSeekProc)      comp_seek,
-                      (TIFFCloseProc)     ig->closecb, 
-                      (TIFFSizeProc)      ig->sizecb,
-                      (TIFFMapFileProc)   NULL,
-                      (TIFFUnmapFileProc) NULL);
-  
-
-
-  if (!tif) {
-    mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
-    return 0;
+  if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   ) { 
+    mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width)); 
+    return 0; 
+  }
+  if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  ) { 
+    mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height)); 
+    return 0; 
+  }
+  if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT)) {
+    mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n")); 
+    return 0; 
+  }
+  if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { 
+    mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n")); 
+    return 0; 
+  }
+  if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,   photometric)) { 
+    mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric)); 
+    return 0; 
+  }
+  if (!TIFFSetField(tif, TIFFTAG_COMPRESSION,   compression)) { 
+    mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression)); 
+    return 0; 
   }
-
-  mm_log((1, "i_writetiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
-  
-  if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   ) { mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width)); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  ) { mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height)); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT)) { mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,   photometric)) { mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric)); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_COMPRESSION,   compression)) { mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression)); return 0; }
   samplesperpixel = channels;
   if (photometric == PHOTOMETRIC_PALETTE) {
     uint16 *out[3];
@@ -503,8 +650,14 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
   switch (compression) {
   case COMPRESSION_JPEG:
     mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
-    if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality)        ) { mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality)); return 0; }
-    if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) { mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode)); return 0; }
+    if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality)        ) { 
+      mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality));
+      return 0; 
+    }
+    if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) { 
+      mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode)); 
+      return 0; 
+    }
     break;
   case COMPRESSION_LZW:
     mm_log((1, "i_writetiff_wiol: lzw compression\n"));
@@ -512,7 +665,10 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
   case COMPRESSION_DEFLATE:
     mm_log((1, "i_writetiff_wiol: deflate compression\n"));
     if (predictor != 0) 
-      if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) { mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor)); return 0; }
+      if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) { 
+        mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor)); 
+        return 0; 
+      }
     break;
   case COMPRESSION_PACKBITS:
     mm_log((1, "i_writetiff_wiol: packbits compression\n"));
@@ -565,27 +721,20 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
       }
     }
     if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) {
-      TIFFClose(tif);
-      i_img_destroy(im);
       i_push_error(0, "cannot set TIFFTAG_XRESOLUTION tag");
       return 0;
     }
     if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) {
-      TIFFClose(tif);
-      i_img_destroy(im);
       i_push_error(0, "cannot set TIFFTAG_YRESOLUTION tag");
       return 0;
     }
     if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) {
-      TIFFClose(tif);
-      i_img_destroy(im);
       i_push_error(0, "cannot set TIFFTAG_RESOLUTIONUNIT tag");
       return 0;
     }
   }
 
   if (!save_tiff_tags(tif, im)) {
-    TIFFClose(tif);
     return 0;
   }
 
@@ -596,7 +745,9 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
         pack_4bit_hl(linebuf, width);
       if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
         mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
-        break;
+        if (linebuf) _TIFFfree(linebuf);
+        if (colors) _TIFFfree(colors);
+        return 0;
       }
     }
   }
@@ -610,67 +761,97 @@ i_writetiff_wiol(i_img *im, io_glue *ig) {
       }
       if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
         mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
-        break;
+        if (linebuf) _TIFFfree(linebuf);
+        if (colors) _TIFFfree(colors);
+        return 0;
       }
     }
   }
-  (void) TIFFClose(tif);
   if (linebuf) _TIFFfree(linebuf);
   if (colors) _TIFFfree(colors);
   return 1;
 }
 
 /*
-=item i_writetiff_wiol_faxable(i_img *, io_glue *)
+=item i_writetiff_multi_wiol(ig, imgs, count, fine_mode)
 
-Stores an image in the iolayer object in faxable tiff format.
+Stores an image in the iolayer object.
 
-   im - image object to write out
    ig - io_object that defines source to write to 
+   imgs,count - the images to write
 
-Note, this may be rewritten to use to simply be a call to a
-lower-level function that gives more options for writing tiff at some
-point.
-
-=cut
+=cut 
 */
 
 undef_int
-i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
-  uint32 width, height;
-  unsigned char *linebuf = NULL;
-  uint32 y;
-  int rc;
-  uint32 x;
+i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
   TIFF* tif;
-  int luma_mask;
-  uint32 rowsperstrip;
-  float vres = fine ? 196 : 98;
-  int luma_chan;
+  int i;
 
-  width    = im->xsize;
-  height   = im->ysize;
+  io_glue_commit_types(ig);
+  i_clear_error();
+  mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n", 
+          ig, imgs, count));
 
-  switch (im->channels) {
-  case 1:
-  case 2:
-    luma_chan = 0;
-    break;
-  case 3:
-  case 4:
-    luma_chan = 1;
-    break;
-  default:
-    /* This means a colorspace we don't handle yet */
-    mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
+  /* FIXME: Enable the mmap interface */
+  
+  tif = TIFFClientOpen("No name", 
+                      "wm",
+                      (thandle_t) ig, 
+                      (TIFFReadWriteProc) ig->readcb,
+                      (TIFFReadWriteProc) ig->writecb,
+                      (TIFFSeekProc)      comp_seek,
+                      (TIFFCloseProc)     ig->closecb, 
+                      (TIFFSizeProc)      ig->sizecb,
+                      (TIFFMapFileProc)   NULL,
+                      (TIFFUnmapFileProc) NULL);
+  
+
+
+  if (!tif) {
+    mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
     return 0;
   }
 
-  /* Add code to get the filename info from the iolayer */
-  /* Also add code to check for mmapped code */
+  for (i = 0; i < count; ++i) {
+    if (!i_writetiff_low(tif, imgs[i])) {
+      TIFFClose(tif);
+      return 0;
+    }
+
+    if (!TIFFWriteDirectory(tif)) {
+      i_push_error(0, "Cannot write TIFF directory");
+      TIFFClose(tif);
+      return 0;
+    }
+  }
+
+  (void) TIFFClose(tif);
+  return 1;
+}
+
+/*
+=item i_writetiff_multi_wiol_faxable(ig, imgs, count, fine_mode)
+
+Stores an image in the iolayer object.
+
+   ig - io_object that defines source to write to 
+   imgs,count - the images to write
+   fine_mode - select fine or normal mode fax images
+
+=cut 
+*/
+
+
+undef_int
+i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
+  TIFF* tif;
+  int i;
 
   io_glue_commit_types(ig);
-  mm_log((1, "i_writetiff_wiol_faxable(im 0x%p, ig 0x%p)\n", im, ig));
+  i_clear_error();
+  mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n", 
+          ig, imgs, count));
 
   /* FIXME: Enable the mmap interface */
   
@@ -684,99 +865,152 @@ i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
                       (TIFFSizeProc)      ig->sizecb,
                       (TIFFMapFileProc)   NULL,
                       (TIFFUnmapFileProc) NULL);
+  
+
 
   if (!tif) {
-    mm_log((1, "i_writetiff_wiol_faxable: Unable to open tif file for writing\n"));
+    mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
     return 0;
   }
 
-  mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
-  
-  if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   )
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  )
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT))
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   1)        )
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
+  for (i = 0; i < count; ++i) {
+    if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
+      TIFFClose(tif);
+      return 0;
+    }
 
-  linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
-  
-  if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
-    mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
+    if (!TIFFWriteDirectory(tif)) {
+      i_push_error(0, "Cannot write TIFF directory");
+      TIFFClose(tif);
+      return 0;
+    }
+  }
 
-  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
-  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
+  (void) TIFFClose(tif);
+  return 1;
+}
 
-  mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
-  mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
-  mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
+/*
+=item i_writetiff_wiol(im, ig)
 
-  if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
-    { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
-  if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
-    mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0; 
+Stores an image in the iolayer object.
+
+   im - image object to write out
+   ig - io_object that defines source to write to 
+
+=cut 
+*/
+undef_int
+i_writetiff_wiol(i_img *img, io_glue *ig) {
+  TIFF* tif;
+  int i;
+
+  io_glue_commit_types(ig);
+  i_clear_error();
+  mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", img, ig));
+
+  /* FIXME: Enable the mmap interface */
+  
+  tif = TIFFClientOpen("No name", 
+                      "wm",
+                      (thandle_t) ig, 
+                      (TIFFReadWriteProc) ig->readcb,
+                      (TIFFReadWriteProc) ig->writecb,
+                      (TIFFSeekProc)      comp_seek,
+                      (TIFFCloseProc)     ig->closecb, 
+                      (TIFFSizeProc)      ig->sizecb,
+                      (TIFFMapFileProc)   NULL,
+                      (TIFFUnmapFileProc) NULL);
+  
+
+
+  if (!tif) {
+    mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
+    return 0;
   }
 
-  if (!save_tiff_tags(tif, im)) {
+  if (!i_writetiff_low(tif, img)) {
     TIFFClose(tif);
     return 0;
   }
 
-  for (y=0; y<height; y++) {
-    int linebufpos=0;
-    for(x=0; x<width; x+=8) { 
-      int bits;
-      int bitpos;
-      i_sample_t luma[8];
-      uint8 bitval = 128;
-      linebuf[linebufpos]=0;
-      bits = width-x; if(bits>8) bits=8;
-      i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
-      for(bitpos=0;bitpos<bits;bitpos++) {
-       linebuf[linebufpos] |= ((luma[bitpos]>=128)?bitval:0);
-       bitval >>= 1;
-      }
-      linebufpos++;
-    }
-    if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
-      mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
-      break;
-    }
+  (void) TIFFClose(tif);
+  return 1;
+}
+
+
+
+/*
+=item i_writetiff_wiol_faxable(i_img *, io_glue *)
+
+Stores an image in the iolayer object in faxable tiff format.
+
+   im - image object to write out
+   ig - io_object that defines source to write to 
+
+Note, this may be rewritten to use to simply be a call to a
+lower-level function that gives more options for writing tiff at some
+point.
+
+=cut
+*/
+
+undef_int
+i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
+  TIFF* tif;
+  int i;
+
+  io_glue_commit_types(ig);
+  i_clear_error();
+  mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", im, ig));
+
+  /* FIXME: Enable the mmap interface */
+  
+  tif = TIFFClientOpen("No name", 
+                      "wm",
+                      (thandle_t) ig, 
+                      (TIFFReadWriteProc) ig->readcb,
+                      (TIFFReadWriteProc) ig->writecb,
+                      (TIFFSeekProc)      comp_seek,
+                      (TIFFCloseProc)     ig->closecb, 
+                      (TIFFSizeProc)      ig->sizecb,
+                      (TIFFMapFileProc)   NULL,
+                      (TIFFUnmapFileProc) NULL);
+  
+
+
+  if (!tif) {
+    mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
+    return 0;
   }
+
+  if (!i_writetiff_low_faxable(tif, im, fine)) {
+    TIFFClose(tif);
+    return 0;
+  }
+
   (void) TIFFClose(tif);
-  if (linebuf) _TIFFfree(linebuf);
   return 1;
 }
 
 static int save_tiff_tags(TIFF *tif, i_img *im) {
   int i;
-
   for (i = 0; i < text_tag_count; ++i) {
     int entry;
     if (i_tags_find(&im->tags, text_tag_names[i].name, 0, &entry)) {
       if (!TIFFSetField(tif, text_tag_names[i].tag, 
-                       im->tags.tags[entry].data)) {
-       i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name);
-       return 0;
+                       im->tags.tags[entry].data)) {
+       i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name);
+       return 0;
       }
     }
   }
-
   return 1;
 }
 
+
 /*
 =item expand_4bit_hl(buf, count)