]> git.imager.perl.org - imager.git/blobdiff - TIFF/imtiff.c
1.005 release
[imager.git] / TIFF / imtiff.c
index d94f686793a95683b18480a9ebe9fd2dde42a677..4bfabcbc44a39bc9d4c294497061f27f46b656ee 100644 (file)
@@ -87,6 +87,18 @@ compress_values[] =
 static const int compress_value_count = 
   sizeof(compress_values) / sizeof(*compress_values);
 
+static struct tag_name
+sample_format_values[] =
+  {
+    { "uint",      SAMPLEFORMAT_UINT },
+    { "int",       SAMPLEFORMAT_INT },
+    { "ieeefp",    SAMPLEFORMAT_IEEEFP },
+    { "undefined", SAMPLEFORMAT_VOID },
+  };
+
+static const int sample_format_value_count = 
+  sizeof(sample_format_values) / sizeof(*sample_format_values);
+
 static int 
 myTIFFIsCODECConfigured(uint16 scheme);
 
@@ -130,6 +142,14 @@ struct read_state_tag {
      we use is EXTRASAMPLE_ASSOCALPHA then the color data will need to
      be scaled to match Imager's conventions */
   int scale_alpha;
+
+  /* number of color samples (not including alpha) */
+  int color_channels;
+
+  /* SampleFormat is 2 */
+  int sample_signed;
+
+  int sample_format;
 };
 
 static int tile_contig_getter(read_state_t *state, read_putter_t putter);
@@ -353,7 +373,7 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
   i_img *im;
   uint32 width, height;
   uint16 samples_per_pixel;
-  int tiled, error;
+  int tiled;
   float xres, yres;
   uint16 resunit;
   int gotXres, gotYres;
@@ -362,6 +382,7 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
   uint16 planar_config;
   uint16 inkset;
   uint16 compress;
+  uint16 sample_format;
   int i;
   read_state_t state;
   read_setup_t setupf = NULL;
@@ -370,8 +391,7 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
   int channels = MAXCHANNELS;
   size_t sample_size = ~0; /* force failure if some code doesn't set it */
   i_img_dim total_pixels;
-
-  error = 0;
+  int samples_integral;
 
   TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
   TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
@@ -382,6 +402,13 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
   TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planar_config);
   TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
 
+  if (samples_per_pixel == 0) {
+    i_push_error(0, "invalid image: SamplesPerPixel is 0");
+    return NULL;
+  }
+
+  TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format);
+
   mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, samples_per_pixel));
   mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
   mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
@@ -395,9 +422,16 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
   state.bits_per_sample = bits_per_sample;
   state.samples_per_pixel = samples_per_pixel;
   state.photometric = photometric;
+  state.sample_signed = sample_format == SAMPLEFORMAT_INT;
+  state.sample_format = sample_format;
+
+  samples_integral = sample_format == SAMPLEFORMAT_UINT
+    || sample_format == SAMPLEFORMAT_INT 
+    || sample_format == SAMPLEFORMAT_VOID;  /* sample as UINT */
 
   /* yes, this if() is horrible */
-  if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8) {
+  if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8
+      && samples_integral) {
     setupf = setup_paletted;
     if (bits_per_sample == 8)
       putterf = paletted_putter8;
@@ -411,28 +445,32 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
   }
   else if (bits_per_sample == 16 
           && photometric == PHOTOMETRIC_RGB
-          && samples_per_pixel >= 3) {
+          && samples_per_pixel >= 3
+          && samples_integral) {
     setupf = setup_16_rgb;
     putterf = putter_16;
     sample_size = 2;
     rgb_channels(&state, &channels);
   }
   else if (bits_per_sample == 16
-          && photometric == PHOTOMETRIC_MINISBLACK) {
+          && photometric == PHOTOMETRIC_MINISBLACK
+          && samples_integral) {
     setupf = setup_16_grey;
     putterf = putter_16;
     sample_size = 2;
     grey_channels(&state, &channels);
   }
   else if (bits_per_sample == 8
-          && photometric == PHOTOMETRIC_MINISBLACK) {
+          && photometric == PHOTOMETRIC_MINISBLACK
+          && samples_integral) {
     setupf = setup_8_grey;
     putterf = putter_8;
     sample_size = 1;
     grey_channels(&state, &channels);
   }
   else if (bits_per_sample == 8
-          && photometric == PHOTOMETRIC_RGB) {
+          && photometric == PHOTOMETRIC_RGB
+          && samples_integral) {
     setupf = setup_8_rgb;
     putterf = putter_8;
     sample_size = 1;
@@ -465,7 +503,8 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
   else if (bits_per_sample == 8
           && photometric == PHOTOMETRIC_SEPARATED
           && inkset == INKSET_CMYK
-          && samples_per_pixel >= 4) {
+          && samples_per_pixel >= 4
+          && samples_integral) {
     setupf = setup_cmyk8;
     putterf = putter_cmyk8;
     sample_size = 1;
@@ -474,7 +513,8 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
   else if (bits_per_sample == 16
           && photometric == PHOTOMETRIC_SEPARATED
           && inkset == INKSET_CMYK
-          && samples_per_pixel >= 4) {
+          && samples_per_pixel >= 4
+          && samples_integral) {
     setupf = setup_cmyk16;
     putterf = putter_cmyk16;
     sample_size = 2;
@@ -607,12 +647,25 @@ static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
       break;
     }
   }
-  
+
+  if (TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sample_format)) {
+    /* only set the tag if the the TIFF tag is present */
+    i_tags_setn(&im->tags, "tiff_sample_format", sample_format);
+
+    for (i = 0; i < sample_format_value_count; ++i) {
+      if (sample_format_values[i].tag == sample_format) {
+       i_tags_set(&im->tags, "tiff_sample_format_name",
+                  sample_format_values[i].name, -1);
+       break;
+      }
+    }
+  }
+
   return im;
 }
 
 /*
-=item i_readtiff_wiol(im, ig)
+=item i_readtiff_wiol(ig, allow_incomplete, page)
 
 =cut
 */
@@ -739,7 +792,7 @@ i_readtiff_multi_wiol(io_glue *ig, int *count) {
   /* Add code to get the filename info from the iolayer */
   /* Also add code to check for mmapped code */
 
-  mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig));
+  mm_log((1, "i_readtiff_wiol(ig %p)\n", ig));
   
   tif = TIFFClientOpen("(Iolayer)", 
                       "rm", 
@@ -867,7 +920,8 @@ i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
   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 scanlinesize=%lu\n",
+         (unsigned long)TIFFScanlineSize(tif) ));
   mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
 
   if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
@@ -2278,6 +2332,7 @@ rgb_channels(read_state_t *state, int *out_channels) {
   *out_channels = 3;
   state->alpha_chan = 0;
   state->scale_alpha = 0;
+  state->color_channels = 3;
 
   /* plain RGB */
   if (state->samples_per_pixel == 3)
@@ -2323,6 +2378,7 @@ grey_channels(read_state_t *state, int *out_channels) {
   *out_channels = 1;
   state->alpha_chan = 0;
   state->scale_alpha = 0;
+  state->color_channels = 1;
 
   /* plain grey */
   if (state->samples_per_pixel == 1)
@@ -2402,6 +2458,10 @@ putter_16(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_
       for (ch = 0; ch < out_chan; ++ch) {
        outp[ch] = p[ch];
       }
+      if (state->sample_signed) {
+       for (ch = 0; ch < state->color_channels; ++ch)
+         outp[ch] ^= 0x8000;
+      }
       if (state->alpha_chan && state->scale_alpha && outp[state->alpha_chan]) {
        for (ch = 0; ch < state->alpha_chan; ++ch) {
          int result = 0.5 + (outp[ch] * 65535.0 / outp[state->alpha_chan]);
@@ -2466,6 +2526,10 @@ putter_8(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_d
       for (ch = 0; ch < out_chan; ++ch) {
        outp->channel[ch] = p[ch];
       }
+      if (state->sample_signed) {
+       for (ch = 0; ch < state->color_channels; ++ch)
+         outp->channel[ch] ^= 0x80;
+      }
       if (state->alpha_chan && state->scale_alpha 
          && outp->channel[state->alpha_chan]) {
        for (ch = 0; ch < state->alpha_chan; ++ch) {
@@ -2529,9 +2593,25 @@ putter_32(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_img_
     i_fcolor *outp = state->line_buf;
 
     for (i = 0; i < width; ++i) {
-      for (ch = 0; ch < out_chan; ++ch) {
-       outp->channel[ch] = p[ch] / 4294967295.0;
+#ifdef IEEEFP_TYPES
+      if (state->sample_format == SAMPLEFORMAT_IEEEFP) {
+       const float *pv = (const float *)p;
+       for (ch = 0; ch < out_chan; ++ch) {
+         outp->channel[ch] = pv[ch];
+       }
+      }
+      else {
+#endif
+       for (ch = 0; ch < out_chan; ++ch) {
+         if (state->sample_signed && ch < state->color_channels)
+           outp->channel[ch] = (p[ch] ^ 0x80000000UL) / 4294967295.0;
+         else
+           outp->channel[ch] = p[ch] / 4294967295.0;
+       }
+#ifdef IEEEFP_TYPES
       }
+#endif
+
       if (state->alpha_chan && state->scale_alpha && outp->channel[state->alpha_chan]) {
        for (ch = 0; ch < state->alpha_chan; ++ch)
          outp->channel[ch] /= outp->channel[state->alpha_chan];
@@ -2616,6 +2696,7 @@ cmyk_channels(read_state_t *state, int *out_channels) {
   *out_channels = 3;
   state->alpha_chan = 0;
   state->scale_alpha = 0;
+  state->color_channels = 3;
 
   /* plain CMYK */
   if (state->samples_per_pixel == 4)
@@ -2680,6 +2761,12 @@ putter_cmyk8(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_i
       m = p[1];
       y = p[2];
       k = 255 - p[3];
+      if (state->sample_signed) {
+       c ^= 0x80;
+       m ^= 0x80;
+       y ^= 0x80;
+       k ^= 0x80;
+      }
       outp->rgba.r = (k * (255 - c)) / 255;
       outp->rgba.g = (k * (255 - m)) / 255;
       outp->rgba.b = (k * (255 - y)) / 255;
@@ -2725,7 +2812,9 @@ putter_cmyk16(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_
   uint16 *p = state->raster;
   int out_chan = state->img->channels;
 
-  mm_log((4, "putter_cmyk16(%p, %d, %d, %d, %d, %d)\n", x, y, width, height, row_extras));
+  mm_log((4, "putter_cmyk16(%p, %" i_DF ", %" i_DF ", %" i_DF
+         ", %" i_DF ", %d)\n", state, i_DFcp(x, y), i_DFcp(width, height),
+         row_extras));
 
   state->pixels_read += width * height;
   while (height > 0) {
@@ -2739,6 +2828,12 @@ putter_cmyk16(read_state_t *state, i_img_dim x, i_img_dim y, i_img_dim width, i_
       m = p[1];
       y = p[2];
       k = 65535 - p[3];
+      if (state->sample_signed) {
+       c ^= 0x8000;
+       m ^= 0x8000;
+       y ^= 0x8000;
+       k ^= 0x8000;
+      }
       outp[0] = (k * (65535U - c)) / 65535U;
       outp[1] = (k * (65535U - m)) / 65535U;
       outp[2] = (k * (65535U - y)) / 65535U;