]> git.imager.perl.org - imager.git/blobdiff - tiff.c
initial version
[imager.git] / tiff.c
diff --git a/tiff.c b/tiff.c
index 8f72bc2754506c0e1f9e567a41a9d68230c95b04..692b00818a504647419265df63a53f08f5ace2ea 100644 (file)
--- a/tiff.c
+++ b/tiff.c
@@ -31,7 +31,6 @@ Some of these functions are internal.
 =cut
 */
 
 =cut
 */
 
-
 #define byteswap_macro(x) \
      ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |     \
       (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
 #define byteswap_macro(x) \
      ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |     \
       (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
@@ -61,12 +60,47 @@ static void error_handler(char const *module, char const *fmt, va_list ap) {
   i_push_errorvf(0, fmt, ap);
 }
 
   i_push_errorvf(0, fmt, ap);
 }
 
+#define WARN_BUFFER_LIMIT 10000
+static char *warn_buffer = NULL;
+static int warn_buffer_size = 0;
+
+static void warn_handler(char const *module, char const *fmt, va_list ap) {
+  char buf[1000];
+
+  buf[0] = '\0';
+#ifdef HAVE_SNPRINTF
+  vsnprintf(buf, sizeof(buf), fmt, ap);
+#else
+  vsprintf(buf, fmt, ap);
+#endif
+  if (!warn_buffer || strlen(warn_buffer)+strlen(buf)+2 > warn_buffer_size) {
+    int new_size = warn_buffer_size + strlen(buf) + 2;
+    char *old_buffer = warn_buffer;
+    if (new_size > WARN_BUFFER_LIMIT) {
+      new_size = WARN_BUFFER_LIMIT;
+    }
+    warn_buffer = myrealloc(warn_buffer, new_size);
+    if (!old_buffer) *warn_buffer = '\0';
+    warn_buffer_size = new_size;
+  }
+  if (strlen(warn_buffer)+strlen(buf)+2 <= warn_buffer_size) {
+    strcat(warn_buffer, buf);
+    strcat(warn_buffer, "\n");
+  }
+}
+
 static int save_tiff_tags(TIFF *tif, i_img *im);
 
 static void expand_4bit_hl(unsigned char *buf, int count);
 
 static void pack_4bit_hl(unsigned char *buf, int count);
 
 static int save_tiff_tags(TIFF *tif, i_img *im);
 
 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)
 
 /*
 =item comp_seek(h, o, w)
 
@@ -86,6 +120,37 @@ comp_seek(thandle_t h, toff_t o, int w) {
   return (toff_t) ig->seekcb(ig, o, w);
 }
 
   return (toff_t) ig->seekcb(ig, o, w);
 }
 
+/*
+=item comp_mmap(thandle_t, tdata_t*, toff_t*)
+
+Dummy mmap stub.
+
+This shouldn't ever be called but newer tifflibs want it anyway.
+
+=cut
+*/
+
+static 
+int
+comp_mmap(thandle_t h, tdata_t*p, toff_t*off) {
+  return -1;
+}
+
+/*
+=item comp_munmap(thandle_t h, tdata_t p, toff_t off)
+
+Dummy munmap stub.
+
+This shouldn't ever be called but newer tifflibs want it anyway.
+
+=cut
+*/
+
+static void
+comp_munmap(thandle_t h, tdata_t p, toff_t off) {
+  /* do nothing */
+}
+
 static i_img *read_one_tiff(TIFF *tif) {
   i_img *im;
   uint32 width, height;
 static i_img *read_one_tiff(TIFF *tif) {
   i_img *im;
   uint32 width, height;
@@ -120,6 +185,9 @@ static i_img *read_one_tiff(TIFF *tif) {
   else {
     im = i_img_empty_ch(NULL, width, height, channels);
   }
   else {
     im = i_img_empty_ch(NULL, width, height, channels);
   }
+
+  if (!im)
+    return NULL;
     
   /* resolution tags */
   TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
     
   /* resolution tags */
   TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
@@ -130,16 +198,28 @@ static i_img *read_one_tiff(TIFF *tif) {
       xres = yres;
     else if (!gotYres)
       yres = xres;
       xres = yres;
     else if (!gotYres)
       yres = xres;
+    i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
     if (resunit == RESUNIT_CENTIMETER) {
       /* from dots per cm to dpi */
       xres *= 2.54;
       yres *= 2.54;
     if (resunit == RESUNIT_CENTIMETER) {
       /* from dots per cm to dpi */
       xres *= 2.54;
       yres *= 2.54;
+      i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "centimeter", -1, 0);
     }
     }
-    i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
-    if (resunit == RESUNIT_NONE)
+    else if (resunit == RESUNIT_NONE) {
       i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
       i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
-    i_tags_set_float(&im->tags, "i_xres", 0, xres);
-    i_tags_set_float(&im->tags, "i_yres", 0, yres);
+      i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "none", -1, 0);
+    }
+    else if (resunit == RESUNIT_INCH) {
+      i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "inch", -1, 0);
+    }
+    else {
+      i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "unknown", -1, 0);
+    }
+    /* tifflib doesn't seem to provide a way to get to the original rational
+       value of these, which would let me provide a more reasonable
+       precision. So make up a number. */
+    i_tags_set_float2(&im->tags, "i_xres", 0, xres, 6);
+    i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6);
   }
 
   /* Text tags */
   }
 
   /* Text tags */
@@ -152,6 +232,12 @@ static i_img *read_one_tiff(TIFF *tif) {
                 strlen(data), 0);
     }
   }
                 strlen(data), 0);
     }
   }
+
+  i_tags_add(&im->tags, "i_format", 0, "tiff", -1, 0);
+  if (warn_buffer && *warn_buffer) {
+    i_tags_add(&im->tags, "i_warning", 0, warn_buffer, -1, 0);
+    *warn_buffer = '\0';
+  }
   
   /*   TIFFPrintDirectory(tif, stdout, 0); good for debugging */
 
   
   /*   TIFFPrintDirectory(tif, stdout, 0); good for debugging */
 
@@ -254,9 +340,13 @@ static i_img *read_one_tiff(TIFF *tif) {
       }
     } else {
       uint32 rowsperstrip, row;
       }
     } else {
       uint32 rowsperstrip, row;
-      TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
-      mm_log((1, "i_readtiff_wiol: rowsperstrip=%d\n", rowsperstrip));
-      
+      int rc = TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+      mm_log((1, "i_readtiff_wiol: rowsperstrip=%d rc = %d\n", rowsperstrip, rc));
+  
+                       if (rc != 1 || rowsperstrip==-1) {
+                               rowsperstrip = height;
+                       }
+    
       raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
       if (!raster) {
         i_img_destroy(im);
       raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
       if (!raster) {
         i_img_destroy(im);
@@ -309,10 +399,14 @@ i_img*
 i_readtiff_wiol(io_glue *ig, int length) {
   TIFF* tif;
   TIFFErrorHandler old_handler;
 i_readtiff_wiol(io_glue *ig, int length) {
   TIFF* tif;
   TIFFErrorHandler old_handler;
+  TIFFErrorHandler old_warn_handler;
   i_img *im;
 
   i_clear_error();
   old_handler = TIFFSetErrorHandler(error_handler);
   i_img *im;
 
   i_clear_error();
   old_handler = TIFFSetErrorHandler(error_handler);
+  old_warn_handler = TIFFSetWarningHandler(warn_handler);
+  if (warn_buffer)
+    *warn_buffer = '\0';
 
   /* Add code to get the filename info from the iolayer */
   /* Also add code to check for mmapped code */
 
   /* Add code to get the filename info from the iolayer */
   /* Also add code to check for mmapped code */
@@ -327,14 +421,15 @@ i_readtiff_wiol(io_glue *ig, int length) {
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc) comp_seek,
                       (TIFFCloseProc) ig->closecb,
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc) comp_seek,
                       (TIFFCloseProc) ig->closecb,
-                      (TIFFSizeProc) ig->sizecb,
-                      (TIFFMapFileProc) NULL,
-                      (TIFFUnmapFileProc) NULL);
+                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+                      (TIFFMapFileProc) comp_mmap,
+                      (TIFFUnmapFileProc) comp_munmap);
   
   if (!tif) {
     mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
     i_push_error(0, "opening file");
     TIFFSetErrorHandler(old_handler);
   
   if (!tif) {
     mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
     i_push_error(0, "opening file");
     TIFFSetErrorHandler(old_handler);
+    TIFFSetWarningHandler(old_warn_handler);
     return NULL;
   }
 
     return NULL;
   }
 
@@ -342,6 +437,7 @@ i_readtiff_wiol(io_glue *ig, int length) {
 
   if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
   TIFFSetErrorHandler(old_handler);
 
   if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
   TIFFSetErrorHandler(old_handler);
+  TIFFSetWarningHandler(old_warn_handler);
   TIFFClose(tif);
   return im;
 }
   TIFFClose(tif);
   return im;
 }
@@ -357,12 +453,16 @@ i_img**
 i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
   TIFF* tif;
   TIFFErrorHandler old_handler;
 i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
   TIFF* tif;
   TIFFErrorHandler old_handler;
+  TIFFErrorHandler old_warn_handler;
   i_img **results = NULL;
   int result_alloc = 0;
   int dirnum = 0;
 
   i_clear_error();
   old_handler = TIFFSetErrorHandler(error_handler);
   i_img **results = NULL;
   int result_alloc = 0;
   int dirnum = 0;
 
   i_clear_error();
   old_handler = TIFFSetErrorHandler(error_handler);
+  old_warn_handler = TIFFSetWarningHandler(warn_handler);
+  if (warn_buffer)
+    *warn_buffer = '\0';
 
   /* Add code to get the filename info from the iolayer */
   /* Also add code to check for mmapped code */
 
   /* Add code to get the filename info from the iolayer */
   /* Also add code to check for mmapped code */
@@ -377,14 +477,15 @@ i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc) comp_seek,
                       (TIFFCloseProc) ig->closecb,
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc) comp_seek,
                       (TIFFCloseProc) ig->closecb,
-                      (TIFFSizeProc) ig->sizecb,
-                      (TIFFMapFileProc) NULL,
-                      (TIFFUnmapFileProc) NULL);
+                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+                      (TIFFMapFileProc) comp_mmap,
+                      (TIFFUnmapFileProc) comp_munmap);
   
   if (!tif) {
     mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
     i_push_error(0, "opening file");
     TIFFSetErrorHandler(old_handler);
   
   if (!tif) {
     mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
     i_push_error(0, "opening file");
     TIFFSetErrorHandler(old_handler);
+    TIFFSetWarningHandler(old_warn_handler);
     return NULL;
   }
 
     return NULL;
   }
 
@@ -402,11 +503,17 @@ i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
         i_img **newresults;
         result_alloc *= 2;
         newresults = myrealloc(results, result_alloc * sizeof(i_img *));
         i_img **newresults;
         result_alloc *= 2;
         newresults = myrealloc(results, result_alloc * sizeof(i_img *));
+       if (!newresults) {
+         i_img_destroy(im); /* don't leak it */
+         break;
+       }
+       results = newresults;
       }
     }
     results[*count-1] = im;
   } while (TIFFSetDirectory(tif, ++dirnum));
 
       }
     }
     results[*count-1] = im;
   } while (TIFFSetDirectory(tif, ++dirnum));
 
+  TIFFSetWarningHandler(old_warn_handler);
   TIFFSetErrorHandler(old_handler);
   TIFFClose(tif);
   return results;
   TIFFSetErrorHandler(old_handler);
   TIFFClose(tif);
   return results;
@@ -419,7 +526,6 @@ i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
   uint32 y;
   int rc;
   uint32 x;
   uint32 y;
   int rc;
   uint32 x;
-  int luma_mask;
   uint32 rowsperstrip;
   float vres = fine ? 196 : 98;
   int luma_chan;
   uint32 rowsperstrip;
   float vres = fine ? 196 : 98;
   int luma_chan;
@@ -531,7 +637,7 @@ i_writetiff_low(TIFF *tif, i_img *im) {
   tsize_t linebytes;
   int ch, ci, rc;
   uint32 x;
   tsize_t linebytes;
   int ch, ci, rc;
   uint32 x;
-  int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
+  int got_xres, got_yres, aspect_only, resunit;
   double xres, yres;
   uint16 bitspersample = 8;
   uint16 samplesperpixel;
   double xres, yres;
   uint16 bitspersample = 8;
   uint16 samplesperpixel;
@@ -596,7 +702,6 @@ i_writetiff_low(TIFF *tif, i_img *im) {
     i_color c;
     int count = i_colorcount(im);
     int size;
     i_color c;
     int count = i_colorcount(im);
     int size;
-    int bits;
     int ch, i;
     
     samplesperpixel = 1;
     int ch, i;
     
     samplesperpixel = 1;
@@ -796,9 +901,9 @@ i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc)      comp_seek,
                       (TIFFCloseProc)     ig->closecb, 
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc)      comp_seek,
                       (TIFFCloseProc)     ig->closecb, 
-                      (TIFFSizeProc)      ig->sizecb,
-                      (TIFFMapFileProc)   NULL,
-                      (TIFFUnmapFileProc) NULL);
+                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+                      (TIFFMapFileProc)   comp_mmap,
+                      (TIFFUnmapFileProc) comp_munmap);
   
 
 
   
 
 
@@ -856,9 +961,9 @@ i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc)      comp_seek,
                       (TIFFCloseProc)     ig->closecb, 
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc)      comp_seek,
                       (TIFFCloseProc)     ig->closecb, 
-                      (TIFFSizeProc)      ig->sizecb,
-                      (TIFFMapFileProc)   NULL,
-                      (TIFFUnmapFileProc) NULL);
+                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+                      (TIFFMapFileProc)   comp_mmap,
+                      (TIFFUnmapFileProc) comp_munmap);
   
 
 
   
 
 
@@ -897,7 +1002,6 @@ Stores an image in the iolayer object.
 undef_int
 i_writetiff_wiol(i_img *img, io_glue *ig) {
   TIFF* tif;
 undef_int
 i_writetiff_wiol(i_img *img, io_glue *ig) {
   TIFF* tif;
-  int i;
 
   io_glue_commit_types(ig);
   i_clear_error();
 
   io_glue_commit_types(ig);
   i_clear_error();
@@ -912,9 +1016,9 @@ i_writetiff_wiol(i_img *img, io_glue *ig) {
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc)      comp_seek,
                       (TIFFCloseProc)     ig->closecb, 
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc)      comp_seek,
                       (TIFFCloseProc)     ig->closecb, 
-                      (TIFFSizeProc)      ig->sizecb,
-                      (TIFFMapFileProc)   NULL,
-                      (TIFFUnmapFileProc) NULL);
+                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+                      (TIFFMapFileProc)   comp_mmap,
+                      (TIFFUnmapFileProc) comp_munmap);
   
 
 
   
 
 
@@ -952,7 +1056,6 @@ point.
 undef_int
 i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
   TIFF* tif;
 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();
 
   io_glue_commit_types(ig);
   i_clear_error();
@@ -967,9 +1070,9 @@ i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc)      comp_seek,
                       (TIFFCloseProc)     ig->closecb, 
                       (TIFFReadWriteProc) ig->writecb,
                       (TIFFSeekProc)      comp_seek,
                       (TIFFCloseProc)     ig->closecb, 
-                      (TIFFSizeProc)      ig->sizecb,
-                      (TIFFMapFileProc)   NULL,
-                      (TIFFUnmapFileProc) NULL);
+                      ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
+                      (TIFFMapFileProc)   comp_mmap,
+                      (TIFFUnmapFileProc) comp_munmap);