00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
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
00042
00043
00044
00045
00046 unsigned short tiff_compression = COMPRESSION_NONE;
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 long tiff_g3options = 0;
00062
00063
00064
00065
00066
00067
00068
00069 unsigned short tiff_fillorder = FILLORDER_MSB2LSB;
00070
00071
00072
00073
00074
00075 short tiff_predictor = 0;
00076
00077
00078
00079 long tiff_rowsperstrip = 0;
00080
00081
00082 #ifndef PHOTOMETRIC_DEPTH
00083 #define PHOTOMETRIC_DEPTH 32768
00084 #endif
00085
00086
00087
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
00107
00108 return 0;
00109 }
00110
00111 static tsize_t
00112 istream_dont_write(thandle_t, tdata_t, tsize_t) {
00113
00114
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
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
00216
00217
00218
00219 PNMFileTypeTIFF::
00220 PNMFileTypeTIFF() {
00221
00222
00223 if (pnmimage_tiff_cat->is_debug()) {
00224 pnmimage_tiff_cat->debug()
00225 << TIFFGetVersion() << "\n";
00226 }
00227 }
00228
00229
00230
00231
00232
00233
00234 string PNMFileTypeTIFF::
00235 get_name() const {
00236 return "TIFF";
00237 }
00238
00239
00240
00241
00242
00243
00244
00245 int PNMFileTypeTIFF::
00246 get_num_extensions() const {
00247 return num_extensions_tiff;
00248 }
00249
00250
00251
00252
00253
00254
00255
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
00265
00266
00267
00268
00269
00270 string PNMFileTypeTIFF::
00271 get_suggested_extension() const {
00272 return "tiff";
00273 }
00274
00275
00276
00277
00278
00279
00280
00281 bool PNMFileTypeTIFF::
00282 has_magic_number() const {
00283 return true;
00284 }
00285
00286
00287
00288
00289
00290
00291
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
00304
00305
00306
00307
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
00318
00319
00320
00321
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
00332
00333
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
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
00398
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
00414
00415
00416
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
00425
00426
00427
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
00558
00559
00560
00561 PNMFileTypeTIFF::Reader::
00562 ~Reader() {
00563 if (tif != (struct tiff *)NULL) {
00564 TIFFClose(tif);
00565 }
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 bool PNMFileTypeTIFF::Reader::
00579 supports_read_row() const {
00580 return true;
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
00590
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
00616
00617
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
00631
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
00754
00755
00756
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
00771
00772
00773
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
00782
00783
00784
00785
00786 xelval PNMFileTypeTIFF::Reader::
00787 next_sample_16(unsigned char *&buf_ptr, int &bits_left) const {
00788
00789
00790 unsigned short result = *(unsigned short *)buf_ptr;
00791 buf_ptr += 2;
00792 return result;
00793 }
00794
00795
00796
00797
00798
00799
00800
00801 xelval PNMFileTypeTIFF::Reader::
00802 next_sample_32(unsigned char *&buf_ptr, int &bits_left) const {
00803
00804
00805 unsigned long result = *(unsigned long *)buf_ptr;
00806 buf_ptr += 2;
00807 return (xelval)result;
00808 }
00809
00810
00811
00812
00813
00814
00815
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
00849
00850
00851
00852 PNMFileTypeTIFF::Writer::
00853 Writer(PNMFileType *type, ostream *file, bool owns_file) :
00854 PNMWriter(type, file, owns_file)
00855 {
00856 }
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
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
00903
00904
00905
00906
00907
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:
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
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
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
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
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
01025 TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
01026
01027 if ( chv == (colorhist_vector) 0 ) {
01028 cht = (colorhash_table) 0;
01029 } else {
01030
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
01039 cht = ppm_colorhisttocolorhash( chv, colors );
01040 ppm_freecolorhist( chv );
01041 }
01042
01043
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
01117
01118
01119
01120
01121
01122
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
01135
01136
01137
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
01150 pnmimage_tiff_cat.warning()
01151 << buffer << "\n";
01152 }
01153
01154
01155
01156
01157
01158
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
01171 pnmimage_tiff_cat.error()
01172 << buffer << "\n";
01173 }
01174
01175
01176
01177
01178
01179
01180
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
01190
01191
01192
01193
01194
01195
01196
01197
01198
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