Panda3D
Loading...
Searching...
No Matches
pnmFileTypeTIFF.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file pnmFileTypeTIFF.cxx
10 * @author drose
11 * @date 2000-06-19
12 */
13
14#include "pnmFileTypeTIFF.h"
15
16#ifdef HAVE_TIFF
17
19
20#include "pnmFileTypeRegistry.h"
21#include "bamReader.h"
22#include "ppmcmap.h"
23#include "pfmFile.h"
24
25// Tiff will want to re-typedef these things.
26#define int8 tiff_int8
27#define uint8 tiff_uint8
28#define int32 tiff_int32
29#define uint32 tiff_uint32
30
31using std::ios;
32using std::istream;
33using std::ostream;
34using std::string;
35
36extern "C" {
37#include <tiff.h>
38#include <tiffio.h>
39}
40
41static const char * const extensions_tiff[] = {
42 "tiff", "tif"
43};
44static const int num_extensions_tiff = sizeof(extensions_tiff) / sizeof(const char *);
45
46// These are configurable parameters to specify TIFF details on output. See
47// tiff.h or type man pnmtotiff for a better explanation of options.
48
49// unsigned short tiff_compression = COMPRESSION_LZW; lzw not supported
50// anymore because of big bad Unisys
51unsigned short tiff_compression = COMPRESSION_NONE;
52
53/* One of:
54 COMPRESSION_NONE
55 COMPRESSION_CCITTRLE
56 COMPRESSION_CCITTFAX3
57 COMPRESSION_CCITTFAX4
58 COMPRESSION_LZW
59 COMPRESSION_JPEG
60 COMPRESSION_NEXT
61 COMPRESSION_CCITTRLEW
62 COMPRESSION_PACKBITS
63 COMPRESSION_THUNDERSCAN
64 */
65
66long tiff_g3options = 0;
67/* One or more of:
68 GROUP3OPT_2DENCODING
69 GROUP3OPT_FILLBITS
70
71 meaningful when tiff_compression == COMPRESSION_CCITTFAX3.
72 */
73
74unsigned short tiff_fillorder = FILLORDER_MSB2LSB;
75/* One of:
76 FILLORDER_MSB2LSB
77 FILLORDER_LSB2MSB
78 */
79
80short tiff_predictor = 0;
81/* 0, 1, or 2; meaningful when tiff_compression == COMPRESSION_LZW. */
82
83
84#ifndef PHOTOMETRIC_DEPTH
85#define PHOTOMETRIC_DEPTH 32768
86#endif
87
88// Here's a number of functions to support the iostream interface via the TIFF
89// library.
90static tsize_t
91istream_read(thandle_t fd, tdata_t buf, tsize_t size) {
92 istream *in = (istream *)fd;
93 in->read((char *)buf, size);
95 return in->gcount();
96}
97
98static tsize_t
99ostream_write(thandle_t fd, tdata_t buf, tsize_t size) {
100 ostream *out = (ostream *)fd;
101 out->write((char *)buf, size);
103 return out->fail() ? (tsize_t)0 : size;
104}
105
106static tsize_t
107ostream_dont_read(thandle_t, tdata_t, tsize_t) {
108 // This no-op variant of istream_read() is passed in when we open the file
109 // for writing only. Shouldn't mix reads and writes.
110 return 0;
111}
112
113static tsize_t
114istream_dont_write(thandle_t, tdata_t, tsize_t) {
115 // This no-op variant of ostream_write() is passed in when we open the file
116 // for reading only. Shouldn't mix reads and writes.
117 return 0;
118}
119
120static toff_t
121istream_seek(thandle_t fd, toff_t off, int whence) {
122 istream *in = (istream *)fd;
123
124 ios_seekdir dir;
125 switch (whence) {
126 case SEEK_SET:
127 dir = ios::beg;
128 break;
129
130 case SEEK_END:
131 dir = ios::end;
132 break;
133
134 case SEEK_CUR:
135 dir = ios::cur;
136 break;
137
138 default:
139 return in->tellg();
140 }
141
142 in->seekg(off, dir);
143
144 if (pnmimage_tiff_cat->is_spam()) {
145 pnmimage_tiff_cat->spam()
146 << "istream_seek(" << (void *)in << ", " << off << ", "
147 << whence << "), result = " << in->tellg() << "\n";
148 }
149 return in->tellg();
150}
151
152static toff_t
153ostream_seek(thandle_t fd, toff_t off, int whence) {
154 ostream *out = (ostream *)fd;
155
156 ios_seekdir dir;
157 switch (whence) {
158 case SEEK_SET:
159 dir = ios::beg;
160 break;
161
162 case SEEK_END:
163 dir = ios::end;
164 break;
165
166 case SEEK_CUR:
167 dir = ios::cur;
168 break;
169
170 default:
171 return out->tellp();
172 }
173
174 out->seekp(off, dir);
175
176 if (pnmimage_tiff_cat->is_spam()) {
177 pnmimage_tiff_cat->spam()
178 << "ostream_seek(" << (void *)out << ", " << off << ", "
179 << whence << "), result = " << out->tellp() << "\n";
180 }
181 return out->tellp();
182}
183
184static int
185iostream_dont_close(thandle_t) {
186 // We don't actually close the file; we'll leave that to PNMReader.
187 return true;
188}
189
190static toff_t
191istream_size(thandle_t fd) {
192 istream *in = (istream *)fd;
193 in->seekg(0, ios::end);
194 return in->tellg();
195}
196
197static toff_t
198ostream_size(thandle_t fd) {
199 ostream *out = (ostream *)fd;
200 out->seekp(0, ios::end);
201 return out->tellp();
202}
203
204static int
205iostream_map(thandle_t, tdata_t*, toff_t*) {
206 return (0);
207}
208
209static void
210iostream_unmap(thandle_t, tdata_t, toff_t) {
211}
212
213bool PNMFileTypeTIFF::_installed_error_handlers = false;
214TypeHandle PNMFileTypeTIFF::_type_handle;
215
216/**
217 *
218 */
219PNMFileTypeTIFF::
220PNMFileTypeTIFF() {
221 // This constructor may run at static init time, so we use the ->
222 // dereferencing convention on the notify category.
223 if (pnmimage_tiff_cat->is_debug()) {
224 pnmimage_tiff_cat->debug()
225 << TIFFGetVersion() << "\n";
226 }
227}
228
229/**
230 * Returns a few words describing the file type.
231 */
232string PNMFileTypeTIFF::
233get_name() const {
234 return "TIFF";
235}
236
237/**
238 * Returns the number of different possible filename extensions associated
239 * with this particular file type.
240 */
241int PNMFileTypeTIFF::
242get_num_extensions() const {
243 return num_extensions_tiff;
244}
245
246/**
247 * Returns the nth possible filename extension associated with this particular
248 * file type, without a leading dot.
249 */
250string PNMFileTypeTIFF::
251get_extension(int n) const {
252 nassertr(n >= 0 && n < num_extensions_tiff, string());
253 return extensions_tiff[n];
254}
255
256/**
257 * Returns a suitable filename extension (without a leading dot) to suggest
258 * for files of this type, or empty string if no suggestions are available.
259 */
260string PNMFileTypeTIFF::
261get_suggested_extension() const {
262 return "tiff";
263}
264
265/**
266 * Returns true if this particular file type uses a magic number to identify
267 * it, false otherwise.
268 */
269bool PNMFileTypeTIFF::
270has_magic_number() const {
271 return true;
272}
273
274/**
275 * Returns true if the indicated "magic number" byte stream (the initial few
276 * bytes read from the file) matches this particular file type, false
277 * otherwise.
278 */
279bool PNMFileTypeTIFF::
280matches_magic_number(const string &magic_number) const {
281 nassertr(magic_number.size() >= 2, false);
282 int mn =
283 ((unsigned char)magic_number[0] << 8) |
284 ((unsigned char)magic_number[1]);
285 return (mn == TIFF_BIGENDIAN || mn == TIFF_LITTLEENDIAN);
286}
287
288/**
289 * Allocates and returns a new PNMReader suitable for reading from this file
290 * type, if possible. If reading from this file type is not supported,
291 * returns NULL.
292 */
293PNMReader *PNMFileTypeTIFF::
294make_reader(istream *file, bool owns_file, const string &magic_number) {
295 init_pnm();
296 install_error_handlers();
297 return new Reader(this, file, owns_file, magic_number);
298}
299
300/**
301 * Allocates and returns a new PNMWriter suitable for reading from this file
302 * type, if possible. If writing files of this type is not supported, returns
303 * NULL.
304 */
305PNMWriter *PNMFileTypeTIFF::
306make_writer(ostream *file, bool owns_file) {
307 init_pnm();
308 install_error_handlers();
309 return new Writer(this, file, owns_file);
310}
311
312/**
313 *
314 */
315PNMFileTypeTIFF::Reader::
316Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
317 PNMReader(type, file, owns_file)
318{
319 bool grayscale = false;
320 int numcolors;
321 int i;
322 unsigned short* redcolormap;
323 unsigned short* greencolormap;
324 unsigned short* bluecolormap;
325
326 // Hope we can putback() more than one character.
327 for (string::reverse_iterator mi = magic_number.rbegin();
328 mi != magic_number.rend();
329 mi++) {
330 _file->putback(*mi);
331 }
332 if (_file->fail()) {
333 pnmimage_tiff_cat.error()
334 << "Unable to put back magic number.\n";
335 _is_valid = false;
336 }
337
338 if (_is_valid) {
339 tif = TIFFClientOpen("TIFF file", "r",
340 (thandle_t) _file,
341 istream_read, istream_dont_write,
342 (TIFFSeekProc)istream_seek,
343 iostream_dont_close, istream_size,
344 iostream_map, iostream_unmap);
345
346 if ( tif == nullptr ) {
347 _is_valid = false;
348 }
349 }
350
351 if (_is_valid) {
352 if ( ! TIFFGetField( tif, TIFFTAG_SAMPLEFORMAT, &sample_format ) )
353 sample_format = SAMPLEFORMAT_UINT;
354 if ( ! TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bps ) )
355 bps = 1;
356 if ( ! TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &spp ) )
357 spp = 1;
358
359 if ( ! TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photomet ) ) {
360 pnmimage_tiff_cat.error()
361 << "Error getting photometric from TIFF file.\n";
362 _is_valid = false;
363
364 } else if (sample_format == SAMPLEFORMAT_IEEEFP) {
365 // Floating-point TIFF. We only accept 32-bit floats.
366 if (bps != 32) {
367 pnmimage_tiff_cat.error()
368 << "Can only read 32-bit float TIFF files, not " << bps << "-bit.\n";
369 _is_valid = false;
370 }
371
372 } else if (sample_format != SAMPLEFORMAT_UINT) {
373 // Can't understand other kinds of sample formats.
374 pnmimage_tiff_cat.error()
375 << "Can't understand sample format\n";
376 _is_valid = false;
377 }
378 }
379
380 if (_is_valid) {
381 unsigned short num_extra_samples;
382 unsigned short *extra_samples = nullptr;
383
384 if (!TIFFGetField(tif, TIFFTAG_EXTRASAMPLES, &num_extra_samples,
385 &extra_samples)) {
386 num_extra_samples = 0;
387 }
388 _num_channels = spp - num_extra_samples;
389 unassoc_alpha_sample = 0;
390 assoc_alpha_sample = 0;
391
392 if (_num_channels == 1 || _num_channels == 3) {
393 // Look for an alpha channel in one of the extra samples, if any.
394 bool got_alpha = false;
395 for (unsigned short s = 0; s < num_extra_samples && !got_alpha; s++) {
396 if (extra_samples[s] == EXTRASAMPLE_UNASSALPHA) {
397 unassoc_alpha_sample = s + _num_channels;
398 _num_channels++;
399 got_alpha = true;
400
401 } else if (extra_samples[s] == EXTRASAMPLE_ASSOCALPHA) {
402 assoc_alpha_sample = s + _num_channels;
403 _num_channels++;
404 got_alpha = true;
405 }
406 }
407
408 // Unfortunately, Photoshop seems to write EXTRASAMPLE_UNSPECIFIED into
409 // the EXTRASAMPLES field for its alpha channels. If we have exactly
410 // one extra channel and it's an UNSPECIFIED channel, assume it's meant
411 // to be alpha.
412 if (!got_alpha && num_extra_samples == 1 &&
413 extra_samples[0] == EXTRASAMPLE_UNSPECIFIED) {
414 unassoc_alpha_sample = _num_channels;
415 _num_channels++;
416 }
417
418 } else if ((_num_channels == 2 || _num_channels == 4) && num_extra_samples == 0) {
419 // If we have a 2- or 4-channel image but the extra samples are not
420 // declared, assume it was written out by a broken TIFF implementation
421 // and that the extra channel is really meant to be alpha.
422 unassoc_alpha_sample = _num_channels - 1;
423 if (pnmimage_tiff_cat.is_debug()) {
424 pnmimage_tiff_cat.debug()
425 << "Assuming last channel of " << spp
426 << "-color image is meant to represent alpha.\n";
427 }
428
429 } else {
430 pnmimage_tiff_cat.error()
431 << "Cannot handle " << spp << "-color image (with "
432 << num_extra_samples << " extra channels).\n";
433 _is_valid = false;
434 }
435 }
436
437 if (_is_valid) {
438 (void) TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &_x_size );
439 (void) TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &_y_size );
440
441 if (pnmimage_tiff_cat.is_debug()) {
442 pnmimage_tiff_cat.debug()
443 << "Reading TIFF image: " << _x_size << " x " << _y_size << "\n"
444 << bps << " bits/sample, " << spp << " samples/pixel\n";
445 }
446
447 _maxval = ( 1 << bps ) - 1;
448 if ( _maxval == 1 && _num_channels == 1 ) {
449 if (pnmimage_tiff_cat.is_debug()) {
450 pnmimage_tiff_cat.debug(false)
451 << "monochrome\n";
452 }
453 grayscale = true;
454 } else {
455 switch ( photomet ) {
456 case PHOTOMETRIC_MINISBLACK:
457 if (pnmimage_tiff_cat.is_debug()) {
458 pnmimage_tiff_cat.debug(false)
459 << _maxval + 1 << " graylevels (min is black)\n";
460 }
461 grayscale = true;
462 break;
463
464 case PHOTOMETRIC_MINISWHITE:
465 if (pnmimage_tiff_cat.is_debug()) {
466 pnmimage_tiff_cat.debug(false)
467 << _maxval + 1 << " graylevels (min is white)\n";
468 }
469 grayscale = true;
470 break;
471
472 case PHOTOMETRIC_PALETTE:
473 if (pnmimage_tiff_cat.is_debug()) {
474 pnmimage_tiff_cat.debug(false)
475 << " colormapped\n";
476 }
477 if ( ! TIFFGetField( tif, TIFFTAG_COLORMAP, &redcolormap, &greencolormap, &bluecolormap ) ) {
478 pnmimage_tiff_cat.error()
479 << "Error getting colormap from TIFF file.\n";
480 _is_valid = false;
481 } else {
482 numcolors = _maxval + 1;
483 if ( numcolors > TIFF_COLORMAP_MAXCOLORS ) {
484 pnmimage_tiff_cat.error()
485 << "Cannot read TIFF file with " << numcolors
486 << " in colormap; max supported is " << TIFF_COLORMAP_MAXCOLORS << "\n";
487 _is_valid = false;
488 } else {
489 _maxval = PNM_MAXMAXVAL;
490 grayscale = false;
491 for ( i = 0; i < numcolors; ++i ) {
492 xelval r, g, b;
493 r = (xelval)(_maxval * (double)(redcolormap[i] / 65535.0));
494 g = (xelval)(_maxval * (double)(greencolormap[i] / 65535.0));
495 b = (xelval)(_maxval * (double)(bluecolormap[i] / 65535.0));
496 PPM_ASSIGN( colormap[i], r, g, b );
497 }
498 }
499 }
500 break;
501
502 case PHOTOMETRIC_RGB:
503 if (pnmimage_tiff_cat.is_debug()) {
504 pnmimage_tiff_cat.debug(false)
505 << "truecolor\n";
506 }
507 grayscale = false;
508 break;
509
510 case PHOTOMETRIC_MASK:
511 pnmimage_tiff_cat.error()
512 << "Don't know how to handle TIFF image with PHOTOMETRIC_MASK.\n";
513 _is_valid = false;
514 break;
515
516 case PHOTOMETRIC_DEPTH:
517 pnmimage_tiff_cat.error()
518 << "Don't know how to handle TIFF image with PHOTOMETRIC_DEPTH.\n";
519 _is_valid = false;
520 break;
521
522 default:
523 pnmimage_tiff_cat.error()
524 << "Unknown photometric " << photomet << " in TIFF image.\n";
525 _is_valid = false;
526 break;
527 }
528 }
529 }
530
531 if (_is_valid ) {
532 if ( _maxval > PNM_MAXMAXVAL ) {
533 pnmimage_tiff_cat.error()
534 << "Cannot read TIFF file with maxval of " << _maxval << "\n";
535 _is_valid = false;
536 }
537 }
538
539 if (_is_valid) {
540 if (grayscale && !is_grayscale()) {
541 _num_channels = (has_alpha()) ? 2 : 1;
542 } else if (!grayscale && is_grayscale()) {
543 _num_channels = (has_alpha()) ? 4 : 3;
544 }
545
546 current_row = 0;
547 }
548}
549
550/**
551 *
552 */
553PNMFileTypeTIFF::Reader::
554~Reader() {
555 if (tif != nullptr) {
556 TIFFClose(tif);
557 }
558}
559
560/**
561 * Returns true if this PNMFileType represents a floating-point image type,
562 * false if it is a normal, integer type. If this returns true, read_pfm() is
563 * implemented instead of read_data().
564 */
565bool PNMFileTypeTIFF::Reader::
566is_floating_point() {
567 return (sample_format == SAMPLEFORMAT_IEEEFP);
568}
569
570/**
571 * Reads floating-point data directly into the indicated PfmFile. Returns
572 * true on success, false on failure.
573 */
574bool PNMFileTypeTIFF::Reader::
575read_pfm(PfmFile &pfm) {
576 if (!is_valid()) {
577 return false;
578 }
579
580 int x_size = get_x_size();
581 int y_size = get_y_size();
582 int num_channels = get_num_channels();
583
584 pfm.clear(x_size, y_size, num_channels);
585 vector_float table;
586 pfm.swap_table(table);
587
588 for (int yi = 0; yi < y_size; ++yi) {
589 float *row = &table[(yi * x_size) * _num_channels];
590
591 if (TIFFReadScanline(tif, row, yi, 0 ) < 0 ) {
592 pnmimage_tiff_cat.error()
593 << "failed a scanline read on row " << yi << "\n";
594 pfm.swap_table(table);
595 return false;
596 }
597 }
598
599 pfm.swap_table(table);
600 return true;
601}
602
603/**
604 * Returns true if this particular PNMReader supports a streaming interface to
605 * reading the data: that is, it is capable of returning the data one row at a
606 * time, via repeated calls to read_row(). Returns false if the only way to
607 * read from this file is all at once, via read_data().
608 */
609bool PNMFileTypeTIFF::Reader::
610supports_read_row() const {
611 return true;
612}
613
614/**
615 * If supports_read_row(), above, returns true, this function may be called
616 * repeatedly to read the image, one horizontal row at a time, beginning from
617 * the top. Returns true if the row is successfully read, false if there is
618 * an error or end of file.
619 */
620bool PNMFileTypeTIFF::Reader::
621read_row(xel *row_data, xelval *alpha_data, int x_size, int) {
622 if (!is_valid()) {
623 return false;
624 }
625
626 size_t scanline_size = (size_t)TIFFScanlineSize(tif);
627 unsigned char *buf = (unsigned char*) alloca(scanline_size);
628
629 int col;
630 xelval gray, sample;
631 xelval r, g, b;
632
633 if ( TIFFReadScanline( tif, buf, current_row, 0 ) < 0 ) {
634 pnmimage_tiff_cat.error()
635 << "Bad data read on line " << current_row << " of TIFF image.\n";
636 return false;
637 }
638
639 unsigned char *buf_ptr = buf;
640 unsigned s;
641 int bits_left = 8;
642
643 // Get a pointer to a function that extracts the next bps-bit sample from
644 // the bitarray. There are a handful of different functions, which are
645 // optimized for different values of bps.
646 xelval (PNMFileTypeTIFF::Reader::*next_sample)(unsigned char *&buf_ptr, int &bits_left) const;
647
648 if (bps < 8) {
649 next_sample = &PNMFileTypeTIFF::Reader::next_sample_lt_8;
650
651 } else if (bps == 8) {
652 next_sample = &PNMFileTypeTIFF::Reader::next_sample_8;
653
654 } else if (bps == 16) {
655 next_sample = &PNMFileTypeTIFF::Reader::next_sample_16;
656
657 } else if (bps == 32) {
658 // Actually, it's not likely that a 32-bit sample will fit within a
659 // xelval. Deal with this when we come to it.
660 next_sample = &PNMFileTypeTIFF::Reader::next_sample_32;
661
662 } else {
663 next_sample = &PNMFileTypeTIFF::Reader::next_sample_general;
664 }
665
666 switch ( photomet ) {
667 case PHOTOMETRIC_MINISBLACK:
668 for ( col = 0; col < x_size; ++col )
669 {
670 sample = (this->*next_sample)(buf_ptr, bits_left);
671 gray = sample;
672
673 for (s = 1; s < spp; s++) {
674 sample = (this->*next_sample)(buf_ptr, bits_left);
675 if (s == unassoc_alpha_sample) {
676 alpha_data[col] = sample;
677
678 } else if (s == assoc_alpha_sample) {
679 alpha_data[col] = sample;
680 if (sample != 0) {
681 gray = (xelval)((float)gray * _maxval / (float)sample);
682 }
683 }
684 }
685 PPM_PUTB(row_data[col], gray);
686 }
687 break;
688
689 case PHOTOMETRIC_MINISWHITE:
690 for ( col = 0; col < x_size; ++col )
691 {
692 sample = (this->*next_sample)(buf_ptr, bits_left);
693 gray = _maxval - sample;
694 for (s = 1; s < spp; s++) {
695 sample = (this->*next_sample)(buf_ptr, bits_left);
696 sample = _maxval - sample;
697
698 if (s == unassoc_alpha_sample) {
699 alpha_data[col] = sample;
700
701 } else if (s == assoc_alpha_sample) {
702 alpha_data[col] = sample;
703 if (sample != 0) {
704 gray = (xelval)((float)gray * _maxval / (float)sample);
705 }
706 }
707 }
708
709 PPM_PUTB(row_data[col], gray);
710 }
711 break;
712
713 case PHOTOMETRIC_PALETTE:
714 for ( col = 0; col < x_size; ++col )
715 {
716 sample = (this->*next_sample)(buf_ptr, bits_left);
717 row_data[col] = colormap[sample];
718
719 for (s = 1; s < spp; s++) {
720 sample = (this->*next_sample)(buf_ptr, bits_left);
721 if (s == unassoc_alpha_sample) {
722 alpha_data[col] = sample;
723
724 } else if (s == assoc_alpha_sample) {
725 alpha_data[col] = sample;
726 if (sample != 0) {
727 r = PPM_GETR(row_data[col]);
728 g = PPM_GETG(row_data[col]);
729 b = PPM_GETB(row_data[col]);
730 r = (xelval)((float)r * _maxval / (float)sample);
731 g = (xelval)((float)g * _maxval / (float)sample);
732 b = (xelval)((float)b * _maxval / (float)sample);
733 PPM_ASSIGN(row_data[col], r, g, b);
734 }
735 }
736 }
737 }
738 break;
739
740 case PHOTOMETRIC_RGB:
741 for ( col = 0; col < x_size; ++col ) {
742 sample = (this->*next_sample)(buf_ptr, bits_left);
743 r = sample;
744 sample = (this->*next_sample)(buf_ptr, bits_left);
745 g = sample;
746 sample = (this->*next_sample)(buf_ptr, bits_left);
747 b = sample;
748
749 for (s = 3; s < spp; s++) {
750 sample = (this->*next_sample)(buf_ptr, bits_left);
751 if (s == unassoc_alpha_sample) {
752 alpha_data[col] = sample;
753
754 } else if (s == assoc_alpha_sample) {
755 alpha_data[col] = sample;
756 if (sample != 0) {
757 r = (xelval)((float)r * _maxval / (float)sample);
758 g = (xelval)((float)g * _maxval / (float)sample);
759 b = (xelval)((float)b * _maxval / (float)sample);
760 }
761 }
762 }
763
764 PPM_ASSIGN(row_data[col], r, g, b);
765 }
766 break;
767
768 default:
769 pnmimage_tiff_cat.error()
770 << "Internal error: unsupported photometric " << photomet << "\n";
771 return false;
772 }
773
774 nassertr(buf_ptr <= buf + scanline_size, false);
775
776 current_row++;
777 return true;
778}
779
780/**
781 * Returns the next color sample from the row, when it is known that bps < 8.
782 */
783xelval PNMFileTypeTIFF::Reader::
784next_sample_lt_8(unsigned char *&buf_ptr, int &bits_left) const {
785 if (bits_left == 0) {
786 ++buf_ptr;
787 bits_left = 8;
788 }
789
790 bits_left -= bps;
791 return (*buf_ptr >> bits_left) & _maxval;
792}
793
794/**
795 * Returns the next color sample from the row, when it is known that bps == 8.
796 */
797xelval PNMFileTypeTIFF::Reader::
798next_sample_8(unsigned char *&buf_ptr, int &bits_left) const {
799 return *buf_ptr++;
800}
801
802/**
803 * Returns the next color sample from the row, when it is known that bps ==
804 * 16.
805 */
806xelval PNMFileTypeTIFF::Reader::
807next_sample_16(unsigned char *&buf_ptr, int &bits_left) const {
808 // The TIFF library has already byte-swapped the values if necessary. Thus,
809 // we only need to treat it as an array of shorts.
810 unsigned short result = *(unsigned short *)buf_ptr;
811 buf_ptr += 2;
812 return result;
813}
814
815/**
816 * Returns the next color sample from the row, when it is known that bps ==
817 * 32.
818 */
819xelval PNMFileTypeTIFF::Reader::
820next_sample_32(unsigned char *&buf_ptr, int &bits_left) const {
821 // The TIFF library has already byte-swapped the values if necessary. Thus,
822 // we only need to treat it as an array of longs.
823 unsigned long result = *(unsigned long *)buf_ptr;
824 buf_ptr += 2;
825 return (xelval)result;
826}
827
828/**
829 * Returns the next color sample from the row, in general. This unpacks an
830 * arbitrary string of bits from the sequence.
831 */
832xelval PNMFileTypeTIFF::Reader::
833next_sample_general(unsigned char *&buf_ptr, int &bits_left) const {
834 unsigned int result = 0;
835 int bits_needed = bps;
836
837 while (bits_needed > 0) {
838 nassertr(bits_left >= 0, 0);
839 if (bits_left == 0) {
840 ++buf_ptr;
841 bits_left = 8;
842 }
843
844 if (bits_needed <= bits_left) {
845 bits_left -= bits_needed;
846 unsigned int mask = (1 << bits_needed) - 1;
847 result |= ((*buf_ptr) >> bits_left) & mask;
848 bits_needed = 0;
849
850 } else {
851 bits_needed -= bits_left;
852 unsigned int mask = (1 << bits_left) - 1;
853 result |= ((*buf_ptr) & mask) << bits_needed;
854 bits_left = 0;
855 }
856 }
857
858 return result;
859}
860
861
862/**
863 *
864 */
865PNMFileTypeTIFF::Writer::
866Writer(PNMFileType *type, ostream *file, bool owns_file) :
867 PNMWriter(type, file, owns_file)
868{
869}
870
871/**
872 * Returns true if this PNMFileType can accept a floating-point image type,
873 * false if it can only accept a normal, integer type. If this returns true,
874 * write_pfm() is implemented.
875 */
876bool PNMFileTypeTIFF::Writer::
877supports_floating_point() {
878 return true;
879}
880
881/**
882 * Returns true if this PNMFileType can accept an integer image type, false if
883 * it can only accept a floating-point type. If this returns true,
884 * write_data() or write_row() is implemented.
885 */
886bool PNMFileTypeTIFF::Writer::
887supports_integer() {
888 return true;
889}
890
891/**
892 * Writes floating-point data from the indicated PfmFile. Returns true on
893 * success, false on failure.
894 */
895bool PNMFileTypeTIFF::Writer::
896write_pfm(const PfmFile &pfm) {
897 struct tiff *tif;
898
899 // Open output file.
900 tif = TIFFClientOpen("TIFF file", "w",
901 (thandle_t) _file,
902 ostream_dont_read, ostream_write,
903 (TIFFSeekProc)ostream_seek,
904 iostream_dont_close, ostream_size,
905 iostream_map, iostream_unmap);
906 if (tif == nullptr) {
907 return false;
908 }
909
910 int x_size = pfm.get_x_size();
911 int y_size = pfm.get_y_size();
912 int num_channels = pfm.get_num_channels();
913
914 int photometric = 0;
915 if (num_channels >= 3) {
916 photometric = PHOTOMETRIC_RGB;
917 }
918
919 // Set TIFF parameters.
920 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, x_size);
921 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, y_size);
922 TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
923 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
924 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
925 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
926 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
927 TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Generated via pnmimage.\n" );
928 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, num_channels);
929 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
930
931 const vector_float &table = pfm.get_table();
932 for (int yi = 0; yi < y_size; ++yi) {
933 const float *row = &table[(yi * x_size) * _num_channels];
934
935 if (TIFFWriteScanline(tif, (tdata_t)row, yi, 0 ) < 0) {
936 pnmimage_tiff_cat.error()
937 << "failed a scanline write on row " << yi << "\n";
938 return false;
939 }
940 }
941
942 TIFFFlushData(tif);
943 TIFFClose(tif);
944
945 return true;
946}
947
948/**
949 * Writes out an entire image all at once, including the header, based on the
950 * image data stored in the given _x_size * _y_size array and alpha pointers.
951 * (If the image type has no alpha channel, alpha is ignored.) Returns the
952 * number of rows correctly written.
953 *
954 * It is the user's responsibility to fill in the header data via calls to
955 * set_x_size(), set_num_channels(), etc., or copy_header_from(), before
956 * calling write_data().
957 *
958 * It is important to delete the PNMWriter class after successfully writing
959 * the data. Failing to do this may result in some data not getting flushed!
960 *
961 * Derived classes need not override this if they instead provide
962 * supports_streaming() and write_row(), below.
963 */
964int PNMFileTypeTIFF::Writer::
965write_data(xel *array, xelval *alpha) {
966 colorhist_vector chv = nullptr;
967 colorhash_table cht;
968 unsigned short
969 red[TIFF_COLORMAP_MAXCOLORS],
970 grn[TIFF_COLORMAP_MAXCOLORS],
971 blu[TIFF_COLORMAP_MAXCOLORS];
972 int row, colors, i;
973 int col;
974 int grayscale = false;
975 struct tiff * tif;
976 short photometric = 0;
977 short samplesperpixel = 0;
978 unsigned short extra_samples[1] = { EXTRASAMPLE_UNASSALPHA };
979 short bitspersample = 0;
980 int bytesperrow = 0;
981 unsigned char* buf;
982 unsigned char* tP;
983
984 switch ( get_color_type() ) {
985 case CT_color:
986 // This call is a bit of fakery to convert our proper 2-d array of xels to
987 // an indirect 2-d array of pixels. We make it look like a single row of
988 // _x_size * _y_size pixels.
989
990 // We can't actually write palettes bigger than 256 colors, regardless of
991 // the number of colors we can read.
992 chv = ppm_computecolorhist( (pixel **)&array, _x_size * _y_size, 1,
993 256, &colors );
994 if ( chv == nullptr ) {
995 pnmimage_tiff_cat.debug()
996 << colors << " colors found; too many for a palette.\n"
997 << "Writing a 24-bit RGB file.\n";
998 grayscale = false;
999 } else {
1000 pnmimage_tiff_cat.debug()
1001 << colors << " colors found; writing an 8-bit palette file.\n";
1002 grayscale = true;
1003 for ( i = 0; i < colors; ++i ) {
1004 xelval r, g, b;
1005
1006 r = PPM_GETR( chv[i].color );
1007 g = PPM_GETG( chv[i].color );
1008 b = PPM_GETB( chv[i].color );
1009 if ( r != g || g != b ) {
1010 grayscale = false;
1011 break;
1012 }
1013 }
1014 }
1015 break;
1016
1017 case CT_two_channel: // We don't yet support two-channel output for TIFF's.
1018 case CT_four_channel:
1019 chv = nullptr;
1020 grayscale = false;
1021 break;
1022
1023 case CT_grayscale:
1024 chv = nullptr;
1025 grayscale = true;
1026 break;
1027
1028 default:
1029 break;
1030 }
1031
1032 /* Open output file. */
1033 tif = TIFFClientOpen("TIFF file", "w",
1034 (thandle_t) _file,
1035 ostream_dont_read, ostream_write,
1036 (TIFFSeekProc)ostream_seek,
1037 iostream_dont_close, ostream_size,
1038 iostream_map, iostream_unmap);
1039 if ( tif == nullptr ) {
1040 return 0;
1041 }
1042
1043 /* Figure out TIFF parameters. */
1044 switch ( get_color_type() ) {
1045 case CT_color:
1046 case CT_four_channel:
1047 if ( chv == nullptr ) {
1048 samplesperpixel = _num_channels;
1049 bitspersample = 8;
1050 photometric = PHOTOMETRIC_RGB;
1051 bytesperrow = _x_size * samplesperpixel;
1052 } else if ( grayscale ) {
1053 samplesperpixel = 1;
1054 bitspersample = std::min(8, pm_maxvaltobits(_maxval));
1055 photometric = PHOTOMETRIC_MINISBLACK;
1056 i = 8 / bitspersample;
1057 bytesperrow = ( _x_size + i - 1 ) / i;
1058 } else {
1059 samplesperpixel = 1;
1060 bitspersample = std::min(8, pm_maxvaltobits(_maxval));
1061 photometric = PHOTOMETRIC_PALETTE;
1062 bytesperrow = _x_size;
1063 }
1064 break;
1065
1066 case CT_grayscale:
1067 case CT_two_channel:
1068 samplesperpixel = _num_channels;
1069 bitspersample = pm_maxvaltobits( _maxval );
1070 photometric = PHOTOMETRIC_MINISBLACK;
1071 i = 8 / bitspersample;
1072 bytesperrow = ( _x_size + i - 1 ) / i;
1073 break;
1074
1075 default:
1076 break;
1077 }
1078
1079 buf = (unsigned char*) alloca( bytesperrow );
1080 if ( buf == nullptr ) {
1081 pnmimage_tiff_cat.error()
1082 << "Can't allocate memory for row buffer\n";
1083 return 0;
1084 }
1085
1086 /* Set TIFF parameters. */
1087 TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, _x_size );
1088 TIFFSetField( tif, TIFFTAG_IMAGELENGTH, _y_size );
1089 TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT );
1090 TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, bitspersample );
1091 TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
1092 TIFFSetField( tif, TIFFTAG_COMPRESSION, tiff_compression );
1093 if ( tiff_compression == COMPRESSION_CCITTFAX3 && tiff_g3options != 0 )
1094 TIFFSetField( tif, TIFFTAG_GROUP3OPTIONS, tiff_g3options );
1095 if ( tiff_compression == COMPRESSION_LZW && tiff_predictor != 0 )
1096 TIFFSetField( tif, TIFFTAG_PREDICTOR, tiff_predictor );
1097 TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric );
1098 TIFFSetField( tif, TIFFTAG_FILLORDER, tiff_fillorder );
1099 // TIFFSetField( tif, TIFFTAG_DOCUMENTNAME, "TIFF Image File");
1100 TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION,
1101 "Generated via pnmimage.\n" );
1102 TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel );
1103 if (has_alpha()) {
1104 TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples);
1105 }
1106 TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
1107
1108 if ( chv == nullptr ) {
1109 cht = nullptr;
1110 } else {
1111 /* Make TIFF colormap. */
1112 for ( i = 0; i < colors; ++i ) {
1113 red[i] = (unsigned short) (PPM_GETR( chv[i].color ) * 65535L / _maxval);
1114 grn[i] = (unsigned short) (PPM_GETG( chv[i].color ) * 65535L / _maxval);
1115 blu[i] = (unsigned short) (PPM_GETB( chv[i].color ) * 65535L / _maxval);
1116 }
1117 TIFFSetField( tif, TIFFTAG_COLORMAP, red, grn, blu );
1118
1119 /* Convert color vector to color hash table, for fast lookup. */
1120 cht = ppm_colorhisttocolorhash( chv, colors );
1121 ppm_freecolorhist( chv );
1122 }
1123
1124 /* Now write the TIFF data. */
1125 for ( row = 0; row < _y_size; ++row ) {
1126 xel *row_data = array + row*_x_size;
1127 xelval *alpha_data = alpha + row*_x_size;
1128
1129 if ( !is_grayscale() && ! grayscale ) {
1130 if ( cht == nullptr ) {
1131 tP = buf;
1132 for ( col = 0; col < _x_size; ++col ) {
1133 *tP++ = (unsigned char)(255 * PPM_GETR(row_data[col]) / _maxval);
1134 *tP++ = (unsigned char)(255 * PPM_GETG(row_data[col]) / _maxval);
1135 *tP++ = (unsigned char)(255 * PPM_GETB(row_data[col]) / _maxval);
1136 if (samplesperpixel==4) {
1137 *tP++ = (unsigned char)(255 * alpha_data[col] / _maxval);
1138 }
1139 }
1140 } else {
1141 tP = buf;
1142 for ( col = 0; col < _x_size; ++col ) {
1143 int s;
1144
1145 s = ppm_lookupcolor( cht, (pixel *)(&row_data[col]) );
1146 if ( s == -1 ) {
1147 pnmimage_tiff_cat.error()
1148 << "Internal error: color not found?!? row=" << row
1149 << " col=" << col << "\n";
1150 if (cht != nullptr) {
1151 ppm_freecolorhash(cht);
1152 }
1153 return 0;
1154 }
1155 *tP++ = (unsigned char) s;
1156 if (samplesperpixel==2) {
1157 *tP++ = (unsigned char)(255 * alpha_data[col] / _maxval);
1158 }
1159 }
1160 }
1161 } else {
1162 xelval bigger_maxval;
1163 int bitshift;
1164 unsigned char byte;
1165 xelval s;
1166
1167 bigger_maxval = pm_bitstomaxval( bitspersample );
1168 bitshift = 8 - bitspersample;
1169 byte = 0;
1170 tP = buf;
1171 for ( col = 0; col < _x_size; ++col ) {
1172 s = PPM_GETB(row_data[col]);
1173 if ( _maxval != bigger_maxval )
1174 s = (xelval)((long) s * bigger_maxval / _maxval);
1175 byte |= s << bitshift;
1176 bitshift -= bitspersample;
1177 if ( bitshift < 0 ) {
1178 *tP++ = byte;
1179 bitshift = 8 - bitspersample;
1180 byte = 0;
1181 }
1182 }
1183 if ( bitshift != 8 - bitspersample )
1184 *tP++ = byte;
1185 }
1186
1187 if ( TIFFWriteScanline( tif, buf, row, 0 ) < 0 ) {
1188 pnmimage_tiff_cat.error()
1189 << "failed a scanline write on row " << row << "\n";
1190 return row;
1191 }
1192 }
1193 TIFFFlushData( tif );
1194 TIFFClose( tif );
1195
1196 if (cht != nullptr) {
1197 ppm_freecolorhash(cht);
1198 }
1199
1200 return _y_size;
1201}
1202
1203/**
1204 * Installs our personal error and warning message handlers if they have not
1205 * already been installed. These methods are used to route the Tiff error
1206 * messages through notify, so we can turn some of them off.
1207 */
1208void PNMFileTypeTIFF::
1209install_error_handlers() {
1210 if (!_installed_error_handlers) {
1211 TIFFSetWarningHandler(tiff_warning);
1212 TIFFSetErrorHandler(tiff_error);
1213 _installed_error_handlers = true;
1214 }
1215}
1216
1217/**
1218 * This is our own warning handler. It is called by the tiff library to issue
1219 * a warning message.
1220 */
1221void PNMFileTypeTIFF::
1222tiff_warning(const char *, const char *format, va_list ap) {
1223 static const int buffer_size = 1024;
1224 char buffer[buffer_size];
1225#if defined(WIN32_VC) || defined(WIN64_VC)
1226 vsprintf(buffer, format, ap);
1227#else
1228 vsnprintf(buffer, buffer_size, format, ap);
1229#endif
1230
1231 // We ignore the module. It seems generally useless to us.
1232 pnmimage_tiff_cat.warning()
1233 << buffer << "\n";
1234}
1235
1236/**
1237 * This is our own error handler. It is called by the tiff library to issue a
1238 * error message.
1239 */
1240void PNMFileTypeTIFF::
1241tiff_error(const char *module, const char *format, va_list ap) {
1242 static const int buffer_size = 1024;
1243 char buffer[buffer_size];
1244#if defined(WIN32_VC) || defined(WIN64_VC)
1245 vsprintf(buffer, format, ap);
1246#else
1247 vsnprintf(buffer, buffer_size, format, ap);
1248#endif
1249
1250 // We ignore the module. It seems generally useless to us.
1251 pnmimage_tiff_cat.error()
1252 << buffer << "\n";
1253}
1254
1255
1256/**
1257 * Registers the current object as something that can be read from a Bam file.
1258 */
1259void PNMFileTypeTIFF::
1260register_with_read_factory() {
1262 register_factory(get_class_type(), make_PNMFileTypeTIFF);
1263}
1264
1265/**
1266 * This method is called by the BamReader when an object of this type is
1267 * encountered in a Bam file; it should allocate and return a new object with
1268 * all the data read.
1269 *
1270 * In the case of the PNMFileType objects, since these objects are all shared,
1271 * we just pull the object from the registry.
1272 */
1273TypedWritable *PNMFileTypeTIFF::
1274make_PNMFileTypeTIFF(const FactoryParams &params) {
1275 return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
1276}
1277
1278#endif // HAVE_TIFF
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition bamReader.I:177
An instance of this class is passed to the Factory when requesting it to do its business and construc...
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition pnmFileType.h:32
int get_x_size() const
Returns the number of pixels in the X direction.
get_num_channels
Returns the number of channels in the image.
int get_y_size() const
Returns the number of pixels in the Y direction.
This is an abstract base class that defines the interface for reading image files of various types.
Definition pnmReader.h:27
This is an abstract base class that defines the interface for writing image files of various types.
Definition pnmWriter.h:27
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
Definition pfmFile.h:31
void swap_table(vector_float &table)
This is a very low-level function that completely exchanges the PfmFile's internal table of floating-...
Definition pfmFile.I:549
const vector_float & get_table() const
This is a very low-level function that returns a read-only reference to the internal table of floatin...
Definition pfmFile.I:538
void clear()
Eliminates all data in the file.
Definition pfmFile.cxx:77
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
Definition thread.I:212
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int pm_maxvaltobits(int maxval)
Returns the number of bits sufficient to hold the indicated maxval value.
int pm_bitstomaxval(int bits)
Returns the highest maxval that can be represented in the indicated number of bits.