Panda3D
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 
18 #include "config_pnmimagetypes.h"
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 
31 using std::ios;
32 using std::istream;
33 using std::ostream;
34 using std::string;
35 
36 extern "C" {
37 #include <tiff.h>
38 #include <tiffio.h>
39 }
40 
41 static const char * const extensions_tiff[] = {
42  "tiff", "tif"
43 };
44 static 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
51 unsigned 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 
66 long tiff_g3options = 0;
67 /* One or more of:
68  GROUP3OPT_2DENCODING
69  GROUP3OPT_FILLBITS
70 
71  meaningful when tiff_compression == COMPRESSION_CCITTFAX3.
72  */
73 
74 unsigned short tiff_fillorder = FILLORDER_MSB2LSB;
75 /* One of:
76  FILLORDER_MSB2LSB
77  FILLORDER_LSB2MSB
78  */
79 
80 short 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.
90 static tsize_t
91 istream_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 
98 static tsize_t
99 ostream_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 
106 static tsize_t
107 ostream_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 
113 static tsize_t
114 istream_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 
120 static toff_t
121 istream_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 
152 static toff_t
153 ostream_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 
184 static int
185 iostream_dont_close(thandle_t) {
186  // We don't actually close the file; we'll leave that to PNMReader.
187  return true;
188 }
189 
190 static toff_t
191 istream_size(thandle_t fd) {
192  istream *in = (istream *)fd;
193  in->seekg(0, ios::end);
194  return in->tellg();
195 }
196 
197 static toff_t
198 ostream_size(thandle_t fd) {
199  ostream *out = (ostream *)fd;
200  out->seekp(0, ios::end);
201  return out->tellp();
202 }
203 
204 static int
205 iostream_map(thandle_t, tdata_t*, toff_t*) {
206  return (0);
207 }
208 
209 static void
210 iostream_unmap(thandle_t, tdata_t, toff_t) {
211 }
212 
213 bool PNMFileTypeTIFF::_installed_error_handlers = false;
214 TypeHandle PNMFileTypeTIFF::_type_handle;
215 
216 /**
217  *
218  */
219 PNMFileTypeTIFF::
220 PNMFileTypeTIFF() {
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  */
232 string PNMFileTypeTIFF::
233 get_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  */
241 int PNMFileTypeTIFF::
242 get_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  */
250 string PNMFileTypeTIFF::
251 get_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  */
260 string PNMFileTypeTIFF::
261 get_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  */
269 bool PNMFileTypeTIFF::
270 has_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  */
279 bool PNMFileTypeTIFF::
280 matches_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  */
293 PNMReader *PNMFileTypeTIFF::
294 make_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  */
305 PNMWriter *PNMFileTypeTIFF::
306 make_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  */
315 PNMFileTypeTIFF::Reader::
316 Reader(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  */
553 PNMFileTypeTIFF::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  */
565 bool PNMFileTypeTIFF::Reader::
566 is_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  */
574 bool PNMFileTypeTIFF::Reader::
575 read_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  */
609 bool PNMFileTypeTIFF::Reader::
610 supports_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  */
620 bool PNMFileTypeTIFF::Reader::
621 read_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  */
783 xelval PNMFileTypeTIFF::Reader::
784 next_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  */
797 xelval PNMFileTypeTIFF::Reader::
798 next_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  */
806 xelval PNMFileTypeTIFF::Reader::
807 next_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  */
819 xelval PNMFileTypeTIFF::Reader::
820 next_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  */
832 xelval PNMFileTypeTIFF::Reader::
833 next_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  */
865 PNMFileTypeTIFF::Writer::
866 Writer(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  */
876 bool PNMFileTypeTIFF::Writer::
877 supports_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  */
886 bool PNMFileTypeTIFF::Writer::
887 supports_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  */
895 bool PNMFileTypeTIFF::Writer::
896 write_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  */
964 int PNMFileTypeTIFF::Writer::
965 write_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*) malloc( 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  return 0;
1151  }
1152  *tP++ = (unsigned char) s;
1153  if (samplesperpixel==2) {
1154  *tP++ = (unsigned char)(255 * alpha_data[col] / _maxval);
1155  }
1156  }
1157  }
1158  } else {
1159  xelval bigger_maxval;
1160  int bitshift;
1161  unsigned char byte;
1162  xelval s;
1163 
1164  bigger_maxval = pm_bitstomaxval( bitspersample );
1165  bitshift = 8 - bitspersample;
1166  byte = 0;
1167  tP = buf;
1168  for ( col = 0; col < _x_size; ++col ) {
1169  s = PPM_GETB(row_data[col]);
1170  if ( _maxval != bigger_maxval )
1171  s = (xelval)((long) s * bigger_maxval / _maxval);
1172  byte |= s << bitshift;
1173  bitshift -= bitspersample;
1174  if ( bitshift < 0 ) {
1175  *tP++ = byte;
1176  bitshift = 8 - bitspersample;
1177  byte = 0;
1178  }
1179  }
1180  if ( bitshift != 8 - bitspersample )
1181  *tP++ = byte;
1182  }
1183 
1184  if ( TIFFWriteScanline( tif, buf, row, 0 ) < 0 ) {
1185  pnmimage_tiff_cat.error()
1186  << "failed a scanline write on row " << row << "\n";
1187  return row;
1188  }
1189  }
1190  TIFFFlushData( tif );
1191  TIFFClose( tif );
1192 
1193  return _y_size;
1194 }
1195 
1196 /**
1197  * Installs our personal error and warning message handlers if they have not
1198  * already been installed. These methods are used to route the Tiff error
1199  * messages through notify, so we can turn some of them off.
1200  */
1201 void PNMFileTypeTIFF::
1202 install_error_handlers() {
1203  if (!_installed_error_handlers) {
1204  TIFFSetWarningHandler(tiff_warning);
1205  TIFFSetErrorHandler(tiff_error);
1206  _installed_error_handlers = true;
1207  }
1208 }
1209 
1210 /**
1211  * This is our own warning handler. It is called by the tiff library to issue
1212  * a warning message.
1213  */
1214 void PNMFileTypeTIFF::
1215 tiff_warning(const char *, const char *format, va_list ap) {
1216  static const int buffer_size = 1024;
1217  char buffer[buffer_size];
1218 #if defined(WIN32_VC) || defined(WIN64_VC)
1219  vsprintf(buffer, format, ap);
1220 #else
1221  vsnprintf(buffer, buffer_size, format, ap);
1222 #endif
1223 
1224  // We ignore the module. It seems generally useless to us.
1225  pnmimage_tiff_cat.warning()
1226  << buffer << "\n";
1227 }
1228 
1229 /**
1230  * This is our own error handler. It is called by the tiff library to issue a
1231  * error message.
1232  */
1233 void PNMFileTypeTIFF::
1234 tiff_error(const char *module, const char *format, va_list ap) {
1235  static const int buffer_size = 1024;
1236  char buffer[buffer_size];
1237 #if defined(WIN32_VC) || defined(WIN64_VC)
1238  vsprintf(buffer, format, ap);
1239 #else
1240  vsnprintf(buffer, buffer_size, format, ap);
1241 #endif
1242 
1243  // We ignore the module. It seems generally useless to us.
1244  pnmimage_tiff_cat.error()
1245  << buffer << "\n";
1246 }
1247 
1248 
1249 /**
1250  * Registers the current object as something that can be read from a Bam file.
1251  */
1252 void PNMFileTypeTIFF::
1253 register_with_read_factory() {
1255  register_factory(get_class_type(), make_PNMFileTypeTIFF);
1256 }
1257 
1258 /**
1259  * This method is called by the BamReader when an object of this type is
1260  * encountered in a Bam file; it should allocate and return a new object with
1261  * all the data read.
1262  *
1263  * In the case of the PNMFileType objects, since these objects are all shared,
1264  * we just pull the object from the registry.
1265  */
1266 TypedWritable *PNMFileTypeTIFF::
1267 make_PNMFileTypeTIFF(const FactoryParams &params) {
1268  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
1269 }
1270 
1271 #endif // HAVE_TIFF
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_channels
Returns the number of channels in the image.
int pm_maxvaltobits(int maxval)
Returns the number of bits sufficient to hold the indicated maxval value.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
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
int get_y_size() const
Returns the number of pixels in the Y direction.
int get_x_size() const
Returns the number of pixels in the X direction.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
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
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
Definition: pfmFile.h:31
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
int pm_bitstomaxval(int bits)
Returns the highest maxval that can be represented in the indicated number of bits.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
bool has_alpha() const
Returns true if the image includes an alpha channel, false otherwise.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_grayscale() const
Returns false if the image is a full-color image, and has red, green, and blue components; true if it...
void clear()
Eliminates all data in the file.
Definition: pfmFile.cxx:77