support floating-point tiff files

This commit is contained in:
David Rose 2014-07-01 17:40:37 +00:00
parent a726ccf303
commit 06b2e69a49
4 changed files with 163 additions and 27 deletions

View File

@ -213,11 +213,10 @@ read(PNMReader *reader) {
// Description: Writes the PFM data to the indicated file, returning // Description: Writes the PFM data to the indicated file, returning
// true on success, false on failure. // true on success, false on failure.
// //
// This can also handle writing a standard image file // If the type implied by the filename extension
// supported by PNMImage, if the filename extension is // supports floating-point, the data will be written
// some image type's extension other than "pfm"; it // directly; otherwise, the floating-point data will be
// will be quietly converted to the appropriate integer // quietly converted to the appropriate integer type.
// type.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool PfmFile:: bool PfmFile::
write(const Filename &fullpath) { write(const Filename &fullpath) {
@ -234,21 +233,6 @@ write(const Filename &fullpath) {
<< "Unable to open " << filename << "\n"; << "Unable to open " << filename << "\n";
return false; 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()) { if (pnmimage_cat.is_debug()) {
pnmimage_cat.debug() pnmimage_cat.debug()

View File

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

View File

@ -21,6 +21,7 @@
#include "pnmFileTypeRegistry.h" #include "pnmFileTypeRegistry.h"
#include "bamReader.h" #include "bamReader.h"
#include "ppmcmap.h" #include "ppmcmap.h"
#include "pfmFile.h"
// Tiff will want to re-typedef these things. // Tiff will want to re-typedef these things.
#define int8 tiff_int8 #define int8 tiff_int8
@ -76,9 +77,6 @@ short tiff_predictor = 0;
/* 0, 1, or 2; meaningful when tiff_compression == COMPRESSION_LZW. */ /* 0, 1, or 2; meaningful when tiff_compression == COMPRESSION_LZW. */
long tiff_rowsperstrip = 0;
/* 0 or any positive number */
#ifndef PHOTOMETRIC_DEPTH #ifndef PHOTOMETRIC_DEPTH
#define PHOTOMETRIC_DEPTH 32768 #define PHOTOMETRIC_DEPTH 32768
#endif #endif
@ -369,6 +367,8 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
} }
if (_is_valid) { if (_is_valid) {
if ( ! TIFFGetField( tif, TIFFTAG_SAMPLEFORMAT, &sample_format ) )
sample_format = SAMPLEFORMAT_UINT;
if ( ! TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bps ) ) if ( ! TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bps ) )
bps = 1; bps = 1;
if ( ! TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &spp ) ) 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() pnmimage_tiff_cat.error()
<< "Error getting photometric from TIFF file.\n"; << "Error getting photometric from TIFF file.\n";
_is_valid = false; _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 // Function: PNMFileTypeTIFF::Reader::supports_read_row
// Access: Public, Virtual // 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 // Function: PNMFileTypeTIFF::Writer::write_data
// Access: Public, Virtual // Access: Public, Virtual
@ -992,8 +1139,6 @@ write_data(xel *array, xelval *alpha) {
break; break;
} }
if ( tiff_rowsperstrip == 0 )
tiff_rowsperstrip = ( 8 * 1024 ) / bytesperrow;
buf = (unsigned char*) malloc( bytesperrow ); buf = (unsigned char*) malloc( bytesperrow );
if ( buf == (unsigned char*) 0 ) { if ( buf == (unsigned char*) 0 ) {
pnmimage_tiff_cat.error() pnmimage_tiff_cat.error()
@ -1004,6 +1149,7 @@ write_data(xel *array, xelval *alpha) {
/* Set TIFF parameters. */ /* Set TIFF parameters. */
TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, _x_size ); TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, _x_size );
TIFFSetField( tif, TIFFTAG_IMAGELENGTH, _y_size ); TIFFSetField( tif, TIFFTAG_IMAGELENGTH, _y_size );
TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT );
TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, bitspersample ); TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, bitspersample );
TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT ); TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
TIFFSetField( tif, TIFFTAG_COMPRESSION, tiff_compression ); TIFFSetField( tif, TIFFTAG_COMPRESSION, tiff_compression );
@ -1020,8 +1166,6 @@ write_data(xel *array, xelval *alpha) {
if (has_alpha()) { if (has_alpha()) {
TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples); 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 ); TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
if ( chv == (colorhist_vector) 0 ) { if ( chv == (colorhist_vector) 0 ) {

View File

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