Browse Source

16-bit-per-sample tiff files

David Rose 20 years ago
parent
commit
995ce8b11a

+ 16 - 11
panda/src/pnmimagetypes/pnmFileTypeBMPWriter.cxx

@@ -268,7 +268,8 @@ BMPwriterow(
         unsigned long   cx,
         unsigned short  bpp,
         int             indexed,
-        colorhash_table cht)
+        colorhash_table cht,
+        xelval maxval)
 {
         BITSTREAM       b;
         unsigned        nbyte = 0;
@@ -299,9 +300,9 @@ BMPwriterow(
 
           for (x = 0; x < cx; x++, row++)
             {
-              PutByte(fp, PPM_GETB(*row));
-              PutByte(fp, PPM_GETG(*row));
-              PutByte(fp, PPM_GETR(*row));
+              PutByte(fp, PPM_GETB(*row) * 255 / maxval);
+              PutByte(fp, PPM_GETG(*row) * 255 / maxval);
+              PutByte(fp, PPM_GETR(*row) * 255 / maxval);
               nbyte += 3;
             }
         }
@@ -329,7 +330,8 @@ BMPwritebits(
         unsigned short  cBitCount,
         pixel         **pixels,
         int             indexed,
-        colorhash_table cht)
+        colorhash_table cht,
+        xelval maxval)
 {
         int             nbyte = 0;
         long            y;
@@ -347,7 +349,8 @@ BMPwritebits(
         for (y = (long)cy - 1; y >= 0; y--)
         {
                 int rc;
-                rc = BMPwriterow(fp, pixels[y], cx, cBitCount, indexed, cht);
+                rc = BMPwriterow(fp, pixels[y], cx, cBitCount, indexed, cht,
+                                 maxval);
 
                 if(rc == -1)
                 {
@@ -460,7 +463,7 @@ BMPEncode(
                 pm_error(er_internal, "BMPEncode");
         }
 
-        nbyte += BMPwritebits(fp, x, y, bpp, pixels, true, cht);
+        nbyte += BMPwritebits(fp, x, y, bpp, pixels, true, cht, 255);
         if(nbyte != BMPlenfile(classv, bpp, x, y))
         {
                 pm_error(er_internal, "BMPEncode");
@@ -476,7 +479,8 @@ BMPEncode24(
         int             classv,
         int             x,
         int             y,
-        pixel         **pixels)
+        pixel         **pixels,
+        xelval maxval)
 {
         unsigned long   nbyte = 0;
         int             bpp = 24;
@@ -493,7 +497,8 @@ BMPEncode24(
                 pm_error(er_internal, "BMPEncode24");
         }
 
-        nbyte += BMPwritebits(fp, x, y, bpp, pixels, false, colorhash_table());
+        nbyte += BMPwritebits(fp, x, y, bpp, pixels, false, colorhash_table(),
+                              maxval);
         if(nbyte != BMPlenfile(classv, bpp, x, y))
         {
                 pm_error(er_internal, "BMPEncode24");
@@ -582,7 +587,7 @@ write_data(xel *array, xelval *) {
   chv = ppm_computecolorhist(pixels, _x_size, _y_size, MAXCOLORS, &colors);
   if (bmp_bpp > 8) {
     // Quietly generate a 24-bit image.
-    BMPEncode24(_file, classv, _x_size, _y_size, pixels);
+    BMPEncode24(_file, classv, _x_size, _y_size, pixels, _maxval);
 
   } else if (chv == (colorhist_vector) 0) {
     if (bmp_bpp != 0) {
@@ -591,7 +596,7 @@ write_data(xel *array, xelval *) {
         << "too many colors for " << bmp_bpp << "-bit image.\n";
     }
 
-    BMPEncode24(_file, classv, _x_size, _y_size, pixels);
+    BMPEncode24(_file, classv, _x_size, _y_size, pixels, _maxval);
 
   } else {
     pnmimage_bmp_cat.debug()

+ 134 - 24
panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx

@@ -582,17 +582,6 @@ supports_read_row() const {
   return true;
 }
 
-#define NEXTSAMPLE \
-  { \
-    if ( bitsleft == 0 ) \
-    { \
-      ++inP; \
-      bitsleft = 8; \
-    } \
-    bitsleft -= bps; \
-    sample = ( *inP >> bitsleft ) & _maxval; \
-  }
-
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMFileTypeTIFF::Reader::read_row
 //       Access: Public, Virtual
@@ -608,7 +597,9 @@ read_row(xel *row_data, xelval *alpha_data) {
     return false;
   }
 
-  unsigned char *buf = (unsigned char*) alloca((size_t)TIFFScanlineSize(tif));
+  size_t scanline_size = (size_t)TIFFScanlineSize(tif);
+  unsigned char *buf = (unsigned char*) alloca(scanline_size);
+  
   int col;
   xelval gray, sample;
   xelval r, g, b;
@@ -619,19 +610,42 @@ read_row(xel *row_data, xelval *alpha_data) {
     return false;
   }
 
-  unsigned char *inP = buf;
+  unsigned char *buf_ptr = buf;
   unsigned s;
-  int bitsleft = 8;
+  int bits_left = 8;
+
+  // Get a pointer to a function that extracts the next bps-bit sample
+  // from the bitarray.  There are a handful of different functions,
+  // which are optimized for different values of bps.
+  xelval (PNMFileTypeTIFF::Reader::*next_sample)(unsigned char *&buf_ptr, int &bits_left) const;
+
+  if (bps < 8) {
+    next_sample = &PNMFileTypeTIFF::Reader::next_sample_lt_8;
+  
+  } else if (bps == 8) {
+    next_sample = &PNMFileTypeTIFF::Reader::next_sample_8;
+
+  } else if (bps == 16) {
+    next_sample = &PNMFileTypeTIFF::Reader::next_sample_16;
+
+  } else if (bps == 32) {
+    // Actually, it's not likely that a 32-bit sample will fit within
+    // a xelval.  Deal with this when we come to it.
+    next_sample = &PNMFileTypeTIFF::Reader::next_sample_32;
+
+  } else {
+    next_sample = &PNMFileTypeTIFF::Reader::next_sample_general;
+  }
 
   switch ( photomet ) {
   case PHOTOMETRIC_MINISBLACK:
     for ( col = 0; col < _x_size; ++col )
       {
-        NEXTSAMPLE;
+        sample = (this->*next_sample)(buf_ptr, bits_left);
         gray = sample;
 
         for (s = 1; s < spp; s++) {
-          NEXTSAMPLE;
+          sample = (this->*next_sample)(buf_ptr, bits_left);
           if (s == unassoc_alpha_sample) {
             alpha_data[col] = sample;
 
@@ -649,10 +663,10 @@ read_row(xel *row_data, xelval *alpha_data) {
   case PHOTOMETRIC_MINISWHITE:
     for ( col = 0; col < _x_size; ++col )
       {
-        NEXTSAMPLE;
+        sample = (this->*next_sample)(buf_ptr, bits_left);
         gray = _maxval - sample;
         for (s = 1; s < spp; s++) {
-          NEXTSAMPLE;
+          sample = (this->*next_sample)(buf_ptr, bits_left);
           sample = _maxval - sample;
 
           if (s == unassoc_alpha_sample) {
@@ -673,11 +687,11 @@ read_row(xel *row_data, xelval *alpha_data) {
   case PHOTOMETRIC_PALETTE:
     for ( col = 0; col < _x_size; ++col )
       {
-        NEXTSAMPLE;
+        sample = (this->*next_sample)(buf_ptr, bits_left);
         row_data[col] = colormap[sample];
 
         for (s = 1; s < spp; s++) {
-          NEXTSAMPLE;
+          sample = (this->*next_sample)(buf_ptr, bits_left);
           if (s == unassoc_alpha_sample) {
             alpha_data[col] = sample;
 
@@ -699,15 +713,15 @@ read_row(xel *row_data, xelval *alpha_data) {
 
   case PHOTOMETRIC_RGB:
     for ( col = 0; col < _x_size; ++col ) {
-      NEXTSAMPLE;
+      sample = (this->*next_sample)(buf_ptr, bits_left);
       r = sample;
-      NEXTSAMPLE;
+      sample = (this->*next_sample)(buf_ptr, bits_left);
       g = sample;
-      NEXTSAMPLE;
+      sample = (this->*next_sample)(buf_ptr, bits_left);
       b = sample;
 
       for (s = 3; s < spp; s++) {
-        NEXTSAMPLE;
+        sample = (this->*next_sample)(buf_ptr, bits_left);
         if (s == unassoc_alpha_sample) {
           alpha_data[col] = sample;
           
@@ -731,10 +745,106 @@ read_row(xel *row_data, xelval *alpha_data) {
     return false;
   }
 
+  nassertr(buf_ptr <= buf + scanline_size, false);
+
   current_row++;
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Reader::next_sample_lt_8
+//       Access: Private
+//  Description: Returns the next color sample from the row, when it
+//               is known that bps < 8.
+////////////////////////////////////////////////////////////////////
+xelval PNMFileTypeTIFF::Reader::
+next_sample_lt_8(unsigned char *&buf_ptr, int &bits_left) const {
+  if (bits_left == 0) {
+    ++buf_ptr;
+    bits_left = 8;
+  }
+
+  bits_left -= bps;
+  return (*buf_ptr >> bits_left) & _maxval;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Reader::next_sample_8
+//       Access: Private
+//  Description: Returns the next color sample from the row, when it
+//               is known that bps == 8.
+////////////////////////////////////////////////////////////////////
+xelval PNMFileTypeTIFF::Reader::
+next_sample_8(unsigned char *&buf_ptr, int &bits_left) const {
+  return *buf_ptr++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Reader::next_sample_16
+//       Access: Private
+//  Description: Returns the next color sample from the row, when it
+//               is known that bps == 16.
+////////////////////////////////////////////////////////////////////
+xelval PNMFileTypeTIFF::Reader::
+next_sample_16(unsigned char *&buf_ptr, int &bits_left) const {
+  // The TIFF library has already byte-swapped the values if
+  // necessary.  Thus, we only need to treat it as an array of shorts.
+  unsigned short result = *(unsigned short *)buf_ptr;
+  buf_ptr += 2;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Reader::next_sample_32
+//       Access: Private
+//  Description: Returns the next color sample from the row, when it
+//               is known that bps == 32.
+////////////////////////////////////////////////////////////////////
+xelval PNMFileTypeTIFF::Reader::
+next_sample_32(unsigned char *&buf_ptr, int &bits_left) const {
+  // The TIFF library has already byte-swapped the values if
+  // necessary.  Thus, we only need to treat it as an array of longs.
+  unsigned long result = *(unsigned long *)buf_ptr;
+  buf_ptr += 2;
+  return (xelval)result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Reader::next_sample_general
+//       Access: Private
+//  Description: Returns the next color sample from the row, in
+//               general.  This unpacks an arbitrary string of bits
+//               from the sequence.
+////////////////////////////////////////////////////////////////////
+xelval PNMFileTypeTIFF::Reader::
+next_sample_general(unsigned char *&buf_ptr, int &bits_left) const {
+  unsigned int result = 0;
+  int bits_needed = bps;
+
+  while (bits_needed > 0) {
+    nassertr(bits_left >= 0, 0);
+    if (bits_left == 0) {
+      ++buf_ptr;
+      bits_left = 8;
+    }
+    
+    if (bits_needed <= bits_left) {
+      bits_left -= bits_needed;
+      unsigned int mask = (1 << bits_needed) - 1;
+      result |= ((*buf_ptr) >> bits_left) & mask;
+      bits_needed = 0;
+      
+    } else {
+      bits_needed -= bits_left;
+      unsigned int mask = (1 << bits_left) - 1;
+      result |= ((*buf_ptr) & mask) << bits_needed;
+      bits_left = 0;
+    }
+  }
+
+  return result;
+}
+
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMFileTypeTIFF::Writer::Constructor

+ 6 - 0
panda/src/pnmimagetypes/pnmFileTypeTIFF.h

@@ -63,6 +63,12 @@ public:
     virtual bool read_row(xel *array, xelval *alpha);
 
   private:
+    xelval next_sample_lt_8(unsigned char *&buf_ptr, int &bits_left) const;
+    xelval next_sample_8(unsigned char *&buf_ptr, int &bits_left) const;
+    xelval next_sample_16(unsigned char *&buf_ptr, int &bits_left) const;
+    xelval next_sample_32(unsigned char *&buf_ptr, int &bits_left) const;
+    xelval next_sample_general(unsigned char *&buf_ptr, int &bits_left) const;
+
     unsigned short photomet;
     unsigned short bps, spp;
     unsigned short unassoc_alpha_sample, assoc_alpha_sample;