Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx

Go to the documentation of this file.
00001 // Filename: pnmFileTypeTIFF.cxx
00002 // Created by:  drose (19Jun00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "pnmFileTypeTIFF.h"
00020 #include "config_pnmimagetypes.h"
00021 
00022 #include "pnmFileTypeRegistry.h"
00023 #include "bamReader.h"
00024 #include "ppmcmap.h"
00025 
00026 // Tiff will want to re-typedef these things.
00027 #define int8 tiff_int8
00028 #define uint8 tiff_uint8
00029 #define int32 tiff_int32
00030 #define uint32 tiff_uint32
00031 
00032 extern "C" {
00033 #include <tiff.h>
00034 #include <tiffio.h>
00035 }
00036 
00037 static const char * const extensions_tiff[] = {
00038   "tiff", "tif"
00039 };
00040 static const int num_extensions_tiff = sizeof(extensions_tiff) / sizeof(const char *);
00041 
00042 // These are configurable parameters to specify TIFF details on
00043 // output.  See tiff.h or type man pnmtotiff for a better explanation
00044 // of options.
00045 
00046 //unsigned short tiff_compression = COMPRESSION_LZW;  // lzw not supported anymore because of big bad Unisys
00047 #ifdef COMPRESSION_DEFLATE
00048 unsigned short tiff_compression = COMPRESSION_DEFLATE;
00049 #else
00050 unsigned short tiff_compression = COMPRESSION_NONE;
00051 #endif
00052 /* One of:
00053    COMPRESSION_NONE
00054    COMPRESSION_CCITTRLE
00055    COMPRESSION_CCITTFAX3
00056    COMPRESSION_CCITTFAX4
00057    COMPRESSION_LZW
00058    COMPRESSION_JPEG
00059    COMPRESSION_NEXT
00060    COMPRESSION_CCITTRLEW
00061    COMPRESSION_PACKBITS
00062    COMPRESSION_THUNDERSCAN
00063    */
00064 
00065 long tiff_g3options = 0;
00066 /* One or more of:
00067    GROUP3OPT_2DENCODING
00068    GROUP3OPT_FILLBITS
00069 
00070    meaningful when tiff_compression == COMPRESSION_CCITTFAX3.
00071    */
00072 
00073 unsigned short tiff_fillorder = FILLORDER_MSB2LSB;
00074 /* One of:
00075    FILLORDER_MSB2LSB
00076    FILLORDER_LSB2MSB
00077    */
00078 
00079 short tiff_predictor = 0;
00080 /* 0, 1, or 2;  meaningful when tiff_compression == COMPRESSION_LZW. */
00081 
00082 
00083 long tiff_rowsperstrip = 0;
00084 /* 0 or any positive number */
00085 
00086 #ifndef PHOTOMETRIC_DEPTH
00087 #define PHOTOMETRIC_DEPTH 32768
00088 #endif
00089 
00090 // Here's a number of functions to support the iostream interface
00091 // via the TIFF library.
00092 static tsize_t
00093 istream_read(thandle_t fd, tdata_t buf, tsize_t size) {
00094   istream *in = (istream *)fd;
00095   in->read((char *)buf, size);
00096   return in->gcount();
00097 }
00098 
00099 static tsize_t
00100 ostream_write(thandle_t fd, tdata_t buf, tsize_t size) {
00101   ostream *out = (ostream *)fd;
00102   out->write((char *)buf, size);
00103   return out->fail() ? (tsize_t)0 : size;
00104 }
00105 
00106 static tsize_t
00107 ostream_dont_read(thandle_t, tdata_t, tsize_t) {
00108   // This no-op variant of istream_read() is passed in when we open the
00109   // file for writing only.  Shouldn't mix reads and writes.
00110   return 0;
00111 }
00112 
00113 static tsize_t
00114 istream_dont_write(thandle_t, tdata_t, tsize_t) {
00115   // This no-op variant of ostream_write() is passed in when we open the
00116   // file for reading only.  Shouldn't mix reads and writes.
00117   return 0;
00118 }
00119 
00120 static toff_t
00121 istream_seek(thandle_t fd, off_t off, int whence) {
00122   istream *in = (istream *)fd;
00123 
00124   ios_seekdir dir;
00125   switch (whence) {
00126   case SEEK_SET:
00127     dir = ios::beg;
00128     break;
00129 
00130   case SEEK_END:
00131     dir = ios::end;
00132     break;
00133 
00134   case SEEK_CUR:
00135     dir = ios::cur;
00136     break;
00137 
00138   default:
00139     return in->tellg();
00140   }
00141 
00142   in->seekg(off, dir);
00143   return in->tellg();
00144 }
00145 
00146 static toff_t
00147 ostream_seek(thandle_t fd, off_t off, int whence) {
00148   ostream *out = (ostream *)fd;
00149 
00150   ios_seekdir dir;
00151   switch (whence) {
00152   case SEEK_SET:
00153     dir = ios::beg;
00154     break;
00155 
00156   case SEEK_END:
00157     dir = ios::end;
00158     break;
00159 
00160   case SEEK_CUR:
00161     dir = ios::cur;
00162     break;
00163 
00164   default:
00165     return out->tellp();
00166   }
00167 
00168   out->seekp(off, dir);
00169   return out->tellp();
00170 }
00171 
00172 static int
00173 iostream_dont_close(thandle_t) {
00174   // We don't actually close the file; we'll leave that to PNMReader.
00175   return true;
00176 }
00177 
00178 static toff_t
00179 istream_size(thandle_t fd) {
00180   istream *in = (istream *)fd;
00181   in->seekg(0, ios::end);
00182   return in->tellg();
00183 }
00184 
00185 static toff_t
00186 ostream_size(thandle_t fd) {
00187   ostream *out = (ostream *)fd;
00188   out->seekp(0, ios::end);
00189   return out->tellp();
00190 }
00191 
00192 static int
00193 iostream_map(thandle_t, tdata_t*, toff_t*) {
00194   return (0);
00195 }
00196 
00197 static void
00198 iostream_unmap(thandle_t, tdata_t, toff_t) {
00199 }
00200 
00201 bool PNMFileTypeTIFF::_installed_error_handlers = false;
00202 TypeHandle PNMFileTypeTIFF::_type_handle;
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: PNMFileTypeTIFF::Constructor
00206 //       Access: Public
00207 //  Description:
00208 ////////////////////////////////////////////////////////////////////
00209 PNMFileTypeTIFF::
00210 PNMFileTypeTIFF() {
00211 }
00212 
00213 ////////////////////////////////////////////////////////////////////
00214 //     Function: PNMFileTypeTIFF::get_name
00215 //       Access: Public, Virtual
00216 //  Description: Returns a few words describing the file type.
00217 ////////////////////////////////////////////////////////////////////
00218 string PNMFileTypeTIFF::
00219 get_name() const {
00220   return "TIFF";
00221 }
00222 
00223 ////////////////////////////////////////////////////////////////////
00224 //     Function: PNMFileTypeTIFF::get_num_extensions
00225 //       Access: Public, Virtual
00226 //  Description: Returns the number of different possible filename
00227 //               extensions associated with this particular file type.
00228 ////////////////////////////////////////////////////////////////////
00229 int PNMFileTypeTIFF::
00230 get_num_extensions() const {
00231   return num_extensions_tiff;
00232 }
00233 
00234 ////////////////////////////////////////////////////////////////////
00235 //     Function: PNMFileTypeTIFF::get_extension
00236 //       Access: Public, Virtual
00237 //  Description: Returns the nth possible filename extension
00238 //               associated with this particular file type, without a
00239 //               leading dot.
00240 ////////////////////////////////////////////////////////////////////
00241 string PNMFileTypeTIFF::
00242 get_extension(int n) const {
00243   nassertr(n >= 0 && n < num_extensions_tiff, string());
00244   return extensions_tiff[n];
00245 }
00246 
00247 ////////////////////////////////////////////////////////////////////
00248 //     Function: PNMFileTypeTIFF::get_suggested_extension
00249 //       Access: Public, Virtual
00250 //  Description: Returns a suitable filename extension (without a
00251 //               leading dot) to suggest for files of this type, or
00252 //               empty string if no suggestions are available.
00253 ////////////////////////////////////////////////////////////////////
00254 string PNMFileTypeTIFF::
00255 get_suggested_extension() const {
00256   return "tiff";
00257 }
00258 
00259 ////////////////////////////////////////////////////////////////////
00260 //     Function: PNMFileTypeTIFF::has_magic_number
00261 //       Access: Public, Virtual
00262 //  Description: Returns true if this particular file type uses a
00263 //               magic number to identify it, false otherwise.
00264 ////////////////////////////////////////////////////////////////////
00265 bool PNMFileTypeTIFF::
00266 has_magic_number() const {
00267   return true;
00268 }
00269 
00270 ////////////////////////////////////////////////////////////////////
00271 //     Function: PNMFileTypeTIFF::matches_magic_number
00272 //       Access: Public, Virtual
00273 //  Description: Returns true if the indicated "magic number" byte
00274 //               stream (the initial few bytes read from the file)
00275 //               matches this particular file type, false otherwise.
00276 ////////////////////////////////////////////////////////////////////
00277 bool PNMFileTypeTIFF::
00278 matches_magic_number(const string &magic_number) const {
00279   nassertr(magic_number.size() >= 2, false);
00280   int mn =
00281     ((unsigned char)magic_number[0] << 8) |
00282     ((unsigned char)magic_number[1]);
00283   return (mn == TIFF_BIGENDIAN || mn == TIFF_LITTLEENDIAN);
00284 }
00285 
00286 ////////////////////////////////////////////////////////////////////
00287 //     Function: PNMFileTypeTIFF::make_reader
00288 //       Access: Public, Virtual
00289 //  Description: Allocates and returns a new PNMReader suitable for
00290 //               reading from this file type, if possible.  If reading
00291 //               from this file type is not supported, returns NULL.
00292 ////////////////////////////////////////////////////////////////////
00293 PNMReader *PNMFileTypeTIFF::
00294 make_reader(istream *file, bool owns_file, const string &magic_number) {
00295   init_pnm();
00296   install_error_handlers();
00297   return new Reader(this, file, owns_file, magic_number);
00298 }
00299 
00300 ////////////////////////////////////////////////////////////////////
00301 //     Function: PNMFileTypeTIFF::make_writer
00302 //       Access: Public, Virtual
00303 //  Description: Allocates and returns a new PNMWriter suitable for
00304 //               reading from this file type, if possible.  If writing
00305 //               files of this type is not supported, returns NULL.
00306 ////////////////////////////////////////////////////////////////////
00307 PNMWriter *PNMFileTypeTIFF::
00308 make_writer(ostream *file, bool owns_file) {
00309   init_pnm();
00310   install_error_handlers();
00311   return new Writer(this, file, owns_file);
00312 }
00313 
00314 ////////////////////////////////////////////////////////////////////
00315 //     Function: PNMFileTypeTIFF::Reader::Constructor
00316 //       Access: Public
00317 //  Description:
00318 ////////////////////////////////////////////////////////////////////
00319 PNMFileTypeTIFF::Reader::
00320 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
00321   PNMReader(type, file, owns_file)
00322 {
00323   bool grayscale = false;
00324   int numcolors;
00325   int i;
00326   unsigned short* redcolormap;
00327   unsigned short* greencolormap;
00328   unsigned short* bluecolormap;
00329 
00330   // Hope we can putback() more than one character.
00331   for (string::reverse_iterator mi = magic_number.rbegin();
00332        mi != magic_number.rend();
00333        mi++) {
00334     _file->putback(*mi);
00335   }
00336   if (_file->fail()) {
00337     pnmimage_tiff_cat.error()
00338       << "Unable to put back magic number.\n";
00339     _is_valid = false;
00340   }
00341 
00342   if (_is_valid) {
00343     tif = TIFFClientOpen("TIFF file", "r",
00344                          (thandle_t) _file,
00345                          istream_read, istream_dont_write,
00346                          (TIFFSeekProc)istream_seek,
00347                          iostream_dont_close, istream_size,
00348                          iostream_map, iostream_unmap);
00349 
00350     if ( tif == NULL ) {
00351       _is_valid = false;
00352     }
00353   }
00354 
00355   if (_is_valid) {
00356     if ( ! TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bps ) )
00357       bps = 1;
00358     if ( ! TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &spp ) )
00359       spp = 1;
00360 
00361     if ( ! TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photomet ) ) {
00362       pnmimage_tiff_cat.error()
00363         << "Error getting photometric from TIFF file.\n";
00364       _is_valid = false;
00365     }
00366   }
00367 
00368   if (_is_valid) {
00369     if (spp >= 1 && spp <= 4) {
00370       _num_channels = spp;
00371     } else {
00372       pnmimage_tiff_cat.error()
00373         << "Cannot handle " << spp << "-channel image.\n";
00374       _is_valid = false;
00375     }
00376   }
00377 
00378   if (_is_valid) {
00379     (void) TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &_x_size );
00380     (void) TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &_y_size );
00381 
00382     if (pnmimage_tiff_cat.is_debug()) {
00383       pnmimage_tiff_cat.debug()
00384         << "Reading TIFF image: " << _x_size << " x " << _y_size << "\n"
00385         << bps << " bits/sample, " << spp << " samples/pixel\n";
00386     }
00387 
00388     _maxval = ( 1 << bps ) - 1;
00389     if ( _maxval == 1 && spp == 1 ) {
00390         if (pnmimage_tiff_cat.is_debug()) {
00391           pnmimage_tiff_cat.debug(false)
00392             << "monochrome\n";
00393         }
00394         grayscale = true;
00395     } else {
00396       switch ( photomet ) {
00397       case PHOTOMETRIC_MINISBLACK:
00398         if (pnmimage_tiff_cat.is_debug()) {
00399           pnmimage_tiff_cat.debug(false)
00400             << _maxval + 1 << " graylevels (min is black)\n";
00401         }
00402         grayscale = true;
00403         break;
00404 
00405       case PHOTOMETRIC_MINISWHITE:
00406         if (pnmimage_tiff_cat.is_debug()) {
00407           pnmimage_tiff_cat.debug(false)
00408             << _maxval + 1 << " graylevels (min is white)\n";
00409         }
00410         grayscale = true;
00411         break;
00412 
00413       case PHOTOMETRIC_PALETTE:
00414         if (pnmimage_tiff_cat.is_debug()) {
00415           pnmimage_tiff_cat.debug(false)
00416             << " colormapped\n";
00417         }
00418         if ( ! TIFFGetField( tif, TIFFTAG_COLORMAP, &redcolormap, &greencolormap, &bluecolormap ) ) {
00419           pnmimage_tiff_cat.error()
00420             << "Error getting colormap from TIFF file.\n";
00421           _is_valid = false;
00422         } else {
00423           numcolors = _maxval + 1;
00424           if ( numcolors > TIFF_COLORMAP_MAXCOLORS ) {
00425             pnmimage_tiff_cat.error()
00426               << "Cannot read TIFF file with " << numcolors
00427               << " in colormap; max supported is " << TIFF_COLORMAP_MAXCOLORS << "\n";
00428             _is_valid = false;
00429           } else {
00430             _maxval = PNM_MAXMAXVAL;
00431             grayscale = false;
00432             for ( i = 0; i < numcolors; ++i ) {
00433               xelval r, g, b;
00434               r = (xelval)(_maxval * (double)(redcolormap[i] / 65535.0));
00435               g = (xelval)(_maxval * (double)(greencolormap[i] / 65535.0));
00436               b = (xelval)(_maxval * (double)(bluecolormap[i] / 65535.0));
00437               PPM_ASSIGN( colormap[i], r, g, b );
00438             }
00439           }
00440         }
00441         break;
00442 
00443       case PHOTOMETRIC_RGB:
00444         if (pnmimage_tiff_cat.is_debug()) {
00445           pnmimage_tiff_cat.debug(false)
00446             << "truecolor\n";
00447         }
00448         grayscale = false;
00449         break;
00450 
00451       case PHOTOMETRIC_MASK:
00452         pnmimage_tiff_cat.error()
00453           << "Don't know how to handle TIFF image with PHOTOMETRIC_MASK.\n";
00454         _is_valid = false;
00455         break;
00456 
00457       case PHOTOMETRIC_DEPTH:
00458         pnmimage_tiff_cat.error()
00459           << "Don't know how to handle TIFF image with PHOTOMETRIC_DEPTH.\n";
00460         _is_valid = false;
00461         break;
00462 
00463       default:
00464         pnmimage_tiff_cat.error()
00465           << "Unknown photometric " << photomet << " in TIFF image.\n";
00466         _is_valid = false;
00467         break;
00468       }
00469     }
00470   }
00471 
00472   if (_is_valid ) {
00473     if ( _maxval > PNM_MAXMAXVAL ) {
00474       pnmimage_tiff_cat.error()
00475         << "Cannot read TIFF file with maxval of " << _maxval << "\n";
00476       _is_valid = false;
00477     }
00478   }
00479 
00480   if (_is_valid) {
00481     if (grayscale && !is_grayscale()) {
00482       _num_channels = (has_alpha()) ? 2 : 1;
00483     } else if (!grayscale && is_grayscale()) {
00484       _num_channels = (has_alpha()) ? 4 : 3;
00485     }
00486 
00487     current_row = 0;
00488   }
00489 }
00490 
00491 ////////////////////////////////////////////////////////////////////
00492 //     Function: PNMFileTypeTIFF::Reader::Destructor
00493 //       Access: Public, Virtual
00494 //  Description:
00495 ////////////////////////////////////////////////////////////////////
00496 PNMFileTypeTIFF::Reader::
00497 ~Reader() {
00498   TIFFClose( tif );
00499 }
00500 
00501 ////////////////////////////////////////////////////////////////////
00502 //     Function: PNMFileTypeTIFF::Reader::supports_read_row
00503 //       Access: Public, Virtual
00504 //  Description: Returns true if this particular PNMReader supports a
00505 //               streaming interface to reading the data: that is, it
00506 //               is capable of returning the data one row at a time,
00507 //               via repeated calls to read_row().  Returns false if
00508 //               the only way to read from this file is all at once,
00509 //               via read_data().
00510 ////////////////////////////////////////////////////////////////////
00511 bool PNMFileTypeTIFF::Reader::
00512 supports_read_row() const {
00513   return true;
00514 }
00515 
00516 #define NEXTSAMPLE \
00517   { \
00518     if ( bitsleft == 0 ) \
00519     { \
00520       ++inP; \
00521       bitsleft = 8; \
00522     } \
00523     bitsleft -= bps; \
00524     sample = ( *inP >> bitsleft ) & _maxval; \
00525   }
00526 
00527 ////////////////////////////////////////////////////////////////////
00528 //     Function: PNMFileTypeTIFF::Reader::read_row
00529 //       Access: Public, Virtual
00530 //  Description: If supports_read_row(), above, returns true, this
00531 //               function may be called repeatedly to read the image,
00532 //               one horizontal row at a time, beginning from the top.
00533 //               Returns true if the row is successfully read, false
00534 //               if there is an error or end of file.
00535 ////////////////////////////////////////////////////////////////////
00536 bool PNMFileTypeTIFF::Reader::
00537 read_row(xel *row_data, xelval *alpha_data) {
00538   if (!is_valid()) {
00539     return false;
00540   }
00541 
00542   unsigned char *buf = (unsigned char*) alloca((size_t)TIFFScanlineSize(tif));
00543   int col;
00544   unsigned char sample;
00545 
00546   if ( TIFFReadScanline( tif, buf, current_row, 0 ) < 0 ) {
00547     pnmimage_tiff_cat.error()
00548       << "Bad data read on line " << current_row << " of TIFF image.\n";
00549     return false;
00550   }
00551 
00552   unsigned char *inP = buf;
00553   int bitsleft = 8;
00554 
00555   switch ( photomet ) {
00556   case PHOTOMETRIC_MINISBLACK:
00557     for ( col = 0; col < _x_size; ++col )
00558       {
00559         NEXTSAMPLE;
00560         PPM_PUTB(row_data[col], sample);
00561         if ( spp == 2 ) {
00562           NEXTSAMPLE;  // Alpha channel
00563           alpha_data[col] = sample;
00564         }
00565       }
00566     break;
00567 
00568   case PHOTOMETRIC_MINISWHITE:
00569     for ( col = 0; col < _x_size; ++col )
00570       {
00571         NEXTSAMPLE;
00572         sample = _maxval - sample;
00573         PPM_PUTB(row_data[col], sample);
00574         if ( spp == 2 ) {
00575           NEXTSAMPLE;  // Alpha channel
00576           alpha_data[col] = sample;
00577         }
00578       }
00579     break;
00580 
00581   case PHOTOMETRIC_PALETTE:
00582     for ( col = 0; col < _x_size; ++col )
00583       {
00584         NEXTSAMPLE;
00585         row_data[col] = colormap[sample];
00586         if ( spp == 2 ) {
00587           NEXTSAMPLE;  // Alpha channel
00588           alpha_data[col] = sample;
00589         }
00590       }
00591     break;
00592 
00593   case PHOTOMETRIC_RGB:
00594     for ( col = 0; col < _x_size; ++col ) {
00595       xelval r, g, b;
00596 
00597       NEXTSAMPLE;
00598       r = sample;
00599       NEXTSAMPLE;
00600       g = sample;
00601       NEXTSAMPLE;
00602       b = sample;
00603       PPM_ASSIGN(row_data[col], r, g, b);
00604       if ( spp == 4 ) {
00605         NEXTSAMPLE;  // Alpha channel
00606         alpha_data[col] = sample;
00607       }
00608     }
00609     break;
00610 
00611   default:
00612     pnmimage_tiff_cat.error()
00613       << "Internal error: unsupported photometric " << photomet << "\n";
00614     return false;
00615   }
00616 
00617   current_row++;
00618   return true;
00619 }
00620 
00621 
00622 ////////////////////////////////////////////////////////////////////
00623 //     Function: PNMFileTypeTIFF::Writer::Constructor
00624 //       Access: Public
00625 //  Description:
00626 ////////////////////////////////////////////////////////////////////
00627 PNMFileTypeTIFF::Writer::
00628 Writer(PNMFileType *type, ostream *file, bool owns_file) :
00629   PNMWriter(type, file, owns_file)
00630 {
00631 }
00632 
00633 ////////////////////////////////////////////////////////////////////
00634 //     Function: PNMFileTypeTIFF::Writer::write_data
00635 //       Access: Public, Virtual
00636 //  Description: Writes out an entire image all at once, including the
00637 //               header, based on the image data stored in the given
00638 //               _x_size * _y_size array and alpha pointers.  (If the
00639 //               image type has no alpha channel, alpha is ignored.)
00640 //               Returns the number of rows correctly written.
00641 //
00642 //               It is the user's responsibility to fill in the header
00643 //               data via calls to set_x_size(), set_num_channels(),
00644 //               etc., or copy_header_from(), before calling
00645 //               write_data().
00646 //
00647 //               It is important to delete the PNMWriter class after
00648 //               successfully writing the data.  Failing to do this
00649 //               may result in some data not getting flushed!
00650 //
00651 //               Derived classes need not override this if they
00652 //               instead provide supports_streaming() and write_row(),
00653 //               below.
00654 ////////////////////////////////////////////////////////////////////
00655 int PNMFileTypeTIFF::Writer::
00656 write_data(xel *array, xelval *alpha) {
00657   colorhist_vector chv = (colorhist_vector) 0;
00658   colorhash_table cht;
00659   unsigned short
00660     red[TIFF_COLORMAP_MAXCOLORS],
00661     grn[TIFF_COLORMAP_MAXCOLORS],
00662     blu[TIFF_COLORMAP_MAXCOLORS];
00663   int row, colors, i;
00664   register int col;
00665   int grayscale = false;
00666   struct tiff * tif;
00667   short photometric = 0;
00668   short samplesperpixel = 0;
00669   short bitspersample = 0;
00670   int bytesperrow = 0;
00671   unsigned char* buf;
00672   unsigned char* tP;
00673 
00674   switch ( get_color_type() ) {
00675   case CT_color:
00676     // This call is a bit of fakery to convert our proper 2-d array of
00677     // xels to an indirect 2-d array of pixels.  We make it look like a
00678     // single row of _x_size * _y_size pixels.
00679     chv = ppm_computecolorhist( (pixel **)&array, _x_size * _y_size, 1,
00680                                 TIFF_COLORMAP_MAXCOLORS, &colors );
00681     if ( chv == (colorhist_vector) 0 ) {
00682       pnmimage_tiff_cat.debug()
00683         << colors << " colors found; too many for a palette.\n"
00684         << "Writing a 24-bit RGB file.\n";
00685       grayscale = false;
00686     } else {
00687       pnmimage_tiff_cat.debug()
00688         << colors << " colors found; writing an 8-bit palette file.\n";
00689       grayscale = true;
00690       for ( i = 0; i < colors; ++i ) {
00691         register xelval r, g, b;
00692 
00693         r = PPM_GETR( chv[i].color );
00694         g = PPM_GETG( chv[i].color );
00695         b = PPM_GETB( chv[i].color );
00696         if ( r != g || g != b ) {
00697           grayscale = false;
00698           break;
00699         }
00700       }
00701     }
00702     break;
00703 
00704   case CT_two_channel:  // We don't yet support two-channel output for TIFF's.
00705   case CT_four_channel:
00706     chv = (colorhist_vector) 0;
00707     grayscale = false;
00708     break;
00709 
00710   case CT_grayscale:
00711     chv = (colorhist_vector) 0;
00712     grayscale = true;
00713     break;
00714 
00715   default:
00716     break;
00717   }
00718 
00719   /* Open output file. */
00720   tif = TIFFClientOpen("TIFF file", "w",
00721                        (thandle_t) _file,
00722                        ostream_dont_read, ostream_write,
00723                        (TIFFSeekProc)ostream_seek,
00724                        iostream_dont_close, ostream_size,
00725                        iostream_map, iostream_unmap);
00726   if ( tif == NULL ) {
00727     return false;
00728   }
00729 
00730   /* Figure out TIFF parameters. */
00731   switch ( get_color_type() ) {
00732   case CT_color:
00733   case CT_four_channel:
00734     if ( chv == (colorhist_vector) 0 ) {
00735       samplesperpixel = _num_channels;
00736       bitspersample = 8;
00737       photometric = PHOTOMETRIC_RGB;
00738       bytesperrow = _x_size * samplesperpixel;
00739     } else if ( grayscale ) {
00740       samplesperpixel = 1;
00741       bitspersample = pm_maxvaltobits( _maxval );
00742       photometric = PHOTOMETRIC_MINISBLACK;
00743       i = 8 / bitspersample;
00744       bytesperrow = ( _x_size + i - 1 ) / i;
00745     } else {
00746       samplesperpixel = 1;
00747       bitspersample = 8;
00748       photometric = PHOTOMETRIC_PALETTE;
00749       bytesperrow = _x_size;
00750     }
00751     break;
00752 
00753   case CT_grayscale:
00754   case CT_two_channel:
00755     samplesperpixel = _num_channels;
00756     bitspersample = pm_maxvaltobits( _maxval );
00757     photometric = PHOTOMETRIC_MINISBLACK;
00758     i = 8 / bitspersample;
00759     bytesperrow = ( _x_size + i - 1 ) / i;
00760     break;
00761 
00762   default:
00763     break;
00764   }
00765 
00766   if ( tiff_rowsperstrip == 0 )
00767     tiff_rowsperstrip = ( 8 * 1024 ) / bytesperrow;
00768   buf = (unsigned char*) malloc( bytesperrow );
00769   if ( buf == (unsigned char*) 0 ) {
00770     pnmimage_tiff_cat.error()
00771       << "Can't allocate memory for row buffer\n";
00772     return 0;
00773   }
00774 
00775   /* Set TIFF parameters. */
00776   TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, _x_size );
00777   TIFFSetField( tif, TIFFTAG_IMAGELENGTH, _y_size );
00778   TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, bitspersample );
00779   TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
00780   TIFFSetField( tif, TIFFTAG_COMPRESSION, tiff_compression );
00781   if ( tiff_compression == COMPRESSION_CCITTFAX3 && tiff_g3options != 0 )
00782     TIFFSetField( tif, TIFFTAG_GROUP3OPTIONS, tiff_g3options );
00783   if ( tiff_compression == COMPRESSION_LZW && tiff_predictor != 0 )
00784     TIFFSetField( tif, TIFFTAG_PREDICTOR, tiff_predictor );
00785   TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric );
00786   TIFFSetField( tif, TIFFTAG_FILLORDER, tiff_fillorder );
00787   //TIFFSetField( tif, TIFFTAG_DOCUMENTNAME, "TIFF Image File");
00788   TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION,
00789                 "Generated via pnmimage.\n" );
00790   TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel );
00791   TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, tiff_rowsperstrip );
00792   /* TIFFSetField( tif, TIFFTAG_STRIPBYTECOUNTS, _y_size / tiff_rowsperstrip ); */
00793   TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
00794 
00795   if ( chv == (colorhist_vector) 0 ) {
00796     cht = (colorhash_table) 0;
00797   } else {
00798     /* Make TIFF colormap. */
00799     for ( i = 0; i < colors; ++i ) {
00800       red[i] = (unsigned short) (PPM_GETR( chv[i].color ) * 65535L / _maxval);
00801       grn[i] = (unsigned short) (PPM_GETG( chv[i].color ) * 65535L / _maxval);
00802       blu[i] = (unsigned short) (PPM_GETB( chv[i].color ) * 65535L / _maxval);
00803     }
00804     TIFFSetField( tif, TIFFTAG_COLORMAP, red, grn, blu );
00805 
00806     /* Convert color vector to color hash table, for fast lookup. */
00807     cht = ppm_colorhisttocolorhash( chv, colors );
00808     ppm_freecolorhist( chv );
00809   }
00810 
00811   /* Now write the TIFF data. */
00812   for ( row = 0; row < _y_size; ++row ) {
00813     xel *row_data = array + row*_x_size;
00814     xelval *alpha_data = alpha + row*_x_size;
00815 
00816     if ( !is_grayscale() && ! grayscale ) {
00817       if ( cht == (colorhash_table) 0 ) {
00818         tP = buf;
00819         for ( col = 0; col < _x_size; ++col ) {
00820           *tP++ = (unsigned char)(255 * PPM_GETR(row_data[col]) / _maxval);
00821           *tP++ = (unsigned char)(255 * PPM_GETG(row_data[col]) / _maxval);
00822           *tP++ = (unsigned char)(255 * PPM_GETB(row_data[col]) / _maxval);
00823           if (samplesperpixel==4) {
00824             *tP++ = (unsigned char)(255 * alpha_data[col] / _maxval);
00825           }
00826         }
00827       } else {
00828         tP = buf;
00829         for ( col = 0; col < _x_size; ++col ) {
00830           register int s;
00831 
00832           s = ppm_lookupcolor( cht, (pixel *)(&row_data[col]) );
00833           if ( s == -1 ) {
00834             pnmimage_tiff_cat.error()
00835               << "Internal error: color not found?!?  row=" << row
00836               << " col=" << col << "\n";
00837             return 0;
00838           }
00839           *tP++ = (unsigned char) s;
00840           if (samplesperpixel==2) {
00841             *tP++ = (unsigned char)(255 * alpha_data[col] / _maxval);
00842           }
00843         }
00844       }
00845     } else {
00846       register xelval bigger_maxval;
00847       register int bitshift;
00848       register unsigned char byte;
00849       register xelval s;
00850 
00851       bigger_maxval = pm_bitstomaxval( bitspersample );
00852       bitshift = 8 - bitspersample;
00853       byte = 0;
00854       tP = buf;
00855       for ( col = 0; col < _x_size; ++col ) {
00856         s = PPM_GETB(row_data[col]);
00857         if ( _maxval != bigger_maxval )
00858           s = (xelval)((long) s * bigger_maxval / _maxval);
00859         byte |= s << bitshift;
00860         bitshift -= bitspersample;
00861         if ( bitshift < 0 ) {
00862           *tP++ = byte;
00863           bitshift = 8 - bitspersample;
00864           byte = 0;
00865         }
00866       }
00867       if ( bitshift != 8 - bitspersample )
00868         *tP++ = byte;
00869     }
00870 
00871     if ( TIFFWriteScanline( tif, buf, row, 0 ) < 0 ) {
00872       pnmimage_tiff_cat.error()
00873         << "failed a scanline write on row " << row << "\n";
00874       return row;
00875     }
00876   }
00877   TIFFFlushData( tif );
00878   TIFFClose( tif );
00879 
00880   return _y_size;
00881 }
00882 
00883 ////////////////////////////////////////////////////////////////////
00884 //     Function: PNMFileTypeTIFF::install_error_handlers
00885 //       Access: Private
00886 //  Description: Installs our personal error and warning message
00887 //               handlers if they have not already been installed.
00888 //               These methods are used to route the Tiff error
00889 //               messages through notify, so we can turn some of them
00890 //               off.
00891 ////////////////////////////////////////////////////////////////////
00892 void PNMFileTypeTIFF::
00893 install_error_handlers() {
00894   if (!_installed_error_handlers) {
00895     TIFFSetWarningHandler(tiff_warning);
00896     TIFFSetErrorHandler(tiff_error);
00897     _installed_error_handlers = true;
00898   }
00899 }
00900 
00901 ////////////////////////////////////////////////////////////////////
00902 //     Function: PNMFileTypeTIFF::tiff_warning
00903 //       Access: Private, Static
00904 //  Description: This is our own warning handler.  It is called by the
00905 //               tiff library to issue a warning message.
00906 ////////////////////////////////////////////////////////////////////
00907 void PNMFileTypeTIFF::
00908 tiff_warning(const char *, const char *format, va_list ap) {
00909   static const int buffer_size = 1024;
00910   char buffer[buffer_size];
00911 #ifdef WIN32_VC
00912   vsprintf(buffer, format, ap);
00913 #else
00914   vsnprintf(buffer, buffer_size, format, ap);
00915 #endif
00916 
00917   // We ignore the module.  It seems generally useless to us.
00918   pnmimage_tiff_cat.warning()
00919     << buffer << "\n";
00920 }
00921 
00922 ////////////////////////////////////////////////////////////////////
00923 //     Function: PNMFileTypeTIFF::tiff_error
00924 //       Access: Private, Static
00925 //  Description: This is our own error handler.  It is called by the
00926 //               tiff library to issue a error message.
00927 ////////////////////////////////////////////////////////////////////
00928 void PNMFileTypeTIFF::
00929 tiff_error(const char *module, const char *format, va_list ap) {
00930   static const int buffer_size = 1024;
00931   char buffer[buffer_size];
00932 #ifdef WIN32_VC
00933   vsprintf(buffer, format, ap);
00934 #else
00935   vsnprintf(buffer, buffer_size, format, ap);
00936 #endif
00937 
00938   // We ignore the module.  It seems generally useless to us.
00939   pnmimage_tiff_cat.error()
00940     << buffer << "\n";
00941 }
00942 
00943 
00944 ////////////////////////////////////////////////////////////////////
00945 //     Function: PNMFileTypeTIFF::register_with_read_factory
00946 //       Access: Public, Static
00947 //  Description: Registers the current object as something that can be
00948 //               read from a Bam file.
00949 ////////////////////////////////////////////////////////////////////
00950 void PNMFileTypeTIFF::
00951 register_with_read_factory() {
00952   BamReader::get_factory()->
00953     register_factory(get_class_type(), make_PNMFileTypeTIFF);
00954 }
00955 
00956 ////////////////////////////////////////////////////////////////////
00957 //     Function: PNMFileTypeTIFF::make_PNMFileTypeTIFF
00958 //       Access: Protected, Static
00959 //  Description: This method is called by the BamReader when an object
00960 //               of this type is encountered in a Bam file; it should
00961 //               allocate and return a new object with all the data
00962 //               read.
00963 //
00964 //               In the case of the PNMFileType objects, since these
00965 //               objects are all shared, we just pull the object from
00966 //               the registry.
00967 ////////////////////////////////////////////////////////////////////
00968 TypedWritable *PNMFileTypeTIFF::
00969 make_PNMFileTypeTIFF(const FactoryParams &params) {
00970   return PNMFileTypeRegistry::get_ptr()->get_type_by_handle(get_class_type());
00971 }

Generated on Fri May 2 00:43:25 2003 for Panda by doxygen1.3