Jelajahi Sumber

support floating-point tiff files

David Rose 11 tahun lalu
induk
melakukan
06b2e69a49

+ 4 - 20
panda/src/pnmimage/pfmFile.cxx

@@ -213,11 +213,10 @@ read(PNMReader *reader) {
 //  Description: Writes the PFM data to the indicated file, returning
 //               true on success, false on failure.
 //
-//               This can also handle writing a standard image file
-//               supported by PNMImage, if the filename extension is
-//               some image type's extension other than "pfm"; it
-//               will be quietly converted to the appropriate integer
-//               type.
+//               If the type implied by the filename extension
+//               supports floating-point, the data will be written
+//               directly; otherwise, the floating-point data will be
+//               quietly converted to the appropriate integer type.
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 write(const Filename &fullpath) {
@@ -234,21 +233,6 @@ write(const Filename &fullpath) {
       << "Unable to open " << filename << "\n";
     return false;
   }
-
-  string extension = downcase(fullpath.get_extension());
-  if (extension != "pfm") {
-    // Maybe we're trying to write a different kind of image file.
-    PNMImage pnm;
-    PNMWriter *writer = pnm.make_writer(&out, false, fullpath, NULL);
-    if (writer != (PNMWriter *)NULL) {
-      // Yep.
-      if (store(pnm)) {
-        return pnm.write(writer);
-      }
-      // Couldn't make an image.  Carry on directly.
-      delete writer;
-    }
-  }
   
   if (pnmimage_cat.is_debug()) {
     pnmimage_cat.debug()

+ 2 - 0
panda/src/pnmimagetypes/pnmFileTypePfm.cxx

@@ -165,6 +165,8 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
     return;
   }
 
+  _maxval = PGM_MAXMAXVAL;
+
   (*_file) >> _x_size >> _y_size >> _scale;
   if (!(*_file)) {
     pnmimage_cat.debug()

+ 151 - 7
panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx

@@ -21,6 +21,7 @@
 #include "pnmFileTypeRegistry.h"
 #include "bamReader.h"
 #include "ppmcmap.h"
+#include "pfmFile.h"
 
 // Tiff will want to re-typedef these things.
 #define int8 tiff_int8
@@ -76,9 +77,6 @@ short tiff_predictor = 0;
 /* 0, 1, or 2;  meaningful when tiff_compression == COMPRESSION_LZW. */
 
 
-long tiff_rowsperstrip = 0;
-/* 0 or any positive number */
-
 #ifndef PHOTOMETRIC_DEPTH
 #define PHOTOMETRIC_DEPTH 32768
 #endif
@@ -369,6 +367,8 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
   }
 
   if (_is_valid) {
+    if ( ! TIFFGetField( tif, TIFFTAG_SAMPLEFORMAT, &sample_format ) )
+      sample_format = SAMPLEFORMAT_UINT;
     if ( ! TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bps ) )
       bps = 1;
     if ( ! TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &spp ) )
@@ -378,6 +378,20 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
       pnmimage_tiff_cat.error()
         << "Error getting photometric from TIFF file.\n";
       _is_valid = false;
+
+    } else if (sample_format == SAMPLEFORMAT_IEEEFP) {
+      // Floating-point TIFF.  We only accept 32-bit floats.
+      if (bps != 32) {
+        pnmimage_tiff_cat.error()
+          << "Can only read 32-bit float TIFF files, not " << bps << "-bit.\n";
+        _is_valid = false;
+      }
+
+    } else if (sample_format != SAMPLEFORMAT_UINT) {
+      // Can't understand other kinds of sample formats.
+      pnmimage_tiff_cat.error()
+        << "Can't understand sample format\n";
+      _is_valid = false;
     }
   }
 
@@ -565,6 +579,54 @@ PNMFileTypeTIFF::Reader::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Reader::is_floating_point
+//       Access: Public, Virtual
+//  Description: Returns true if this PNMFileType represents a
+//               floating-point image type, false if it is a normal,
+//               integer type.  If this returns true, read_pfm() is
+//               implemented instead of read_data().
+////////////////////////////////////////////////////////////////////
+bool PNMFileTypeTIFF::Reader::
+is_floating_point() {
+  return sample_format = SAMPLEFORMAT_IEEEFP;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Reader::read_pfm
+//       Access: Public, Virtual
+//  Description: Reads floating-point data directly into the indicated
+//               PfmFile.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool PNMFileTypeTIFF::Reader::
+read_pfm(PfmFile &pfm) {
+  if (!is_valid()) {
+    return false;
+  }
+
+  int x_size = get_x_size();
+  int y_size = get_y_size();
+  int num_channels = get_num_channels();
+
+  pfm.clear(x_size, y_size, num_channels);
+  vector_float table;
+  pfm.swap_table(table);
+
+  for (int yi = 0; yi < y_size; ++yi) {
+    float *row = &table[(yi * x_size) * _num_channels];
+
+    if (TIFFReadScanline(tif, row, yi, 0 ) < 0 ) {
+      pnmimage_tiff_cat.error()
+        << "failed a scanline read on row " << yi << "\n";
+      pfm.swap_table(table);
+      return false;
+    }
+  }
+
+  pfm.swap_table(table);
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMFileTypeTIFF::Reader::supports_read_row
 //       Access: Public, Virtual
@@ -855,6 +917,91 @@ Writer(PNMFileType *type, ostream *file, bool owns_file) :
 {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Writer::supports_floating_point
+//       Access: Public, Virtual
+//  Description: Returns true if this PNMFileType can accept a
+//               floating-point image type, false if it can only
+//               accept a normal, integer type.  If this returns true,
+//               write_pfm() is implemented.
+////////////////////////////////////////////////////////////////////
+bool PNMFileTypeTIFF::Writer::
+supports_floating_point() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Writer::supports_integer
+//       Access: Public, Virtual
+//  Description: Returns true if this PNMFileType can accept an
+//               integer image type, false if it can only
+//               accept a floating-point type.  If this returns true,
+//               write_data() or write_row() is implemented.
+////////////////////////////////////////////////////////////////////
+bool PNMFileTypeTIFF::Writer::
+supports_integer() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMFileTypeTIFF::Writer::write_pfm
+//       Access: Public, Virtual
+//  Description: Writes floating-point data from the indicated
+//               PfmFile.  Returns true on success, false on failure.
+////////////////////////////////////////////////////////////////////
+bool PNMFileTypeTIFF::Writer::
+write_pfm(const PfmFile &pfm) {
+  struct tiff *tif;
+
+  // Open output file.
+  tif = TIFFClientOpen("TIFF file", "w",
+                       (thandle_t) _file,
+                       ostream_dont_read, ostream_write,
+                       (TIFFSeekProc)ostream_seek,
+                       iostream_dont_close, ostream_size,
+                       iostream_map, iostream_unmap);
+  if (tif == NULL) {
+    return false;
+  }
+
+  int x_size = pfm.get_x_size();
+  int y_size = pfm.get_y_size();
+  int num_channels = pfm.get_num_channels();
+
+  int photometric = 0;
+  if (num_channels >= 3) {
+    photometric = PHOTOMETRIC_RGB;
+  }
+
+  // Set TIFF parameters.
+  TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, x_size);
+  TIFFSetField(tif, TIFFTAG_IMAGELENGTH, y_size);
+  TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
+  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
+  TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
+  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+  TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Generated via pnmimage.\n" );
+  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, num_channels);
+  TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+
+  const vector_float &table = pfm.get_table();
+  for (int yi = 0; yi < y_size; ++yi) {
+    const float *row = &table[(yi * x_size) * _num_channels];
+    
+    if (TIFFWriteScanline(tif, (tdata_t)row, yi, 0 ) < 0) {
+      pnmimage_tiff_cat.error()
+        << "failed a scanline write on row " << yi << "\n";
+      return false;
+    }
+  }
+
+  TIFFFlushData(tif);
+  TIFFClose(tif);
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMFileTypeTIFF::Writer::write_data
 //       Access: Public, Virtual
@@ -992,8 +1139,6 @@ write_data(xel *array, xelval *alpha) {
     break;
   }
 
-  if ( tiff_rowsperstrip == 0 )
-    tiff_rowsperstrip = ( 8 * 1024 ) / bytesperrow;
   buf = (unsigned char*) malloc( bytesperrow );
   if ( buf == (unsigned char*) 0 ) {
     pnmimage_tiff_cat.error()
@@ -1004,6 +1149,7 @@ write_data(xel *array, xelval *alpha) {
   /* Set TIFF parameters. */
   TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, _x_size );
   TIFFSetField( tif, TIFFTAG_IMAGELENGTH, _y_size );
+  TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT );
   TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, bitspersample );
   TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
   TIFFSetField( tif, TIFFTAG_COMPRESSION, tiff_compression );
@@ -1020,8 +1166,6 @@ write_data(xel *array, xelval *alpha) {
   if (has_alpha()) {
     TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples);
   }
-  TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, tiff_rowsperstrip );
-  /* TIFFSetField( tif, TIFFTAG_STRIPBYTECOUNTS, _y_size / tiff_rowsperstrip ); */
   TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
 
   if ( chv == (colorhist_vector) 0 ) {

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

@@ -55,6 +55,8 @@ public:
     Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number);
     virtual ~Reader();
 
+    virtual bool is_floating_point();
+    virtual bool read_pfm(PfmFile &pfm);
     virtual bool supports_read_row() const;
     virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);
 
@@ -65,6 +67,7 @@ public:
     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 sample_format;
     unsigned short photomet;
     unsigned short bps, spp;
     unsigned short unassoc_alpha_sample, assoc_alpha_sample;
@@ -78,6 +81,9 @@ public:
   public:
     Writer(PNMFileType *type, ostream *file, bool owns_file);
 
+    virtual bool supports_floating_point();
+    virtual bool supports_integer();
+    virtual bool write_pfm(const PfmFile &pfm);
     virtual int write_data(xel *array, xelval *alpha);
   };