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