Panda3D
|
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 ¶ms) { 01202 return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type()); 01203 } 01204 01205 #endif // HAVE_TIFF