Panda3D
pnmFileTypeTGA.cxx
1 // Filename: pnmFileTypeTGA.cxx
2 // Created by: drose (27Apr01)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 
16 // Much code in this file is borrowed from Netpbm, specifically tgatoppm.c
17 // and ppmtotga.c.
18 
19 /* tgatoppm.c - read a TrueVision Targa file and write a portable pixmap
20 **
21 ** Partially based on tga2rast, version 1.0, by Ian MacPhedran.
22 **
23 ** Copyright (C) 1989 by Jef Poskanzer.
24 **
25 ** Permission to use, copy, modify, and distribute this software and its
26 ** documentation for any purpose and without fee is hereby granted, provided
27 ** that the above copyright notice appear in all copies and that both that
28 ** copyright notice and this permission notice appear in supporting
29 ** documentation. This software is provided "as is" without express or
30 ** implied warranty.
31 */
32 
33 /* ppmtotga.c - read a portable pixmap and produce a TrueVision Targa file
34 **
35 ** Copyright (C) 1989, 1991 by Mark Shand and Jef Poskanzer
36 **
37 ** Permission to use, copy, modify, and distribute this software and its
38 ** documentation for any purpose and without fee is hereby granted, provided
39 ** that the above copyright notice appear in all copies and that both that
40 ** copyright notice and this permission notice appear in supporting
41 ** documentation. This software is provided "as is" without express or
42 ** implied warranty.
43 */
44 
45 #include "pnmFileTypeTGA.h"
46 
47 #ifdef HAVE_TGA
48 
49 #include "config_pnmimagetypes.h"
50 
51 #include "pnmFileTypeRegistry.h"
52 #include "bamReader.h"
53 #include "pnmimage_base.h"
54 
55 #include <string.h>
56 
57 static const char * const extensions_tga[] = {
58  "tga"
59 };
60 static const int num_extensions_tga = sizeof(extensions_tga) / sizeof(const char *);
61 
62 TypeHandle PNMFileTypeTGA::_type_handle;
63 
64 
65 /* Header definition. */
66 struct ImageHeader {
67  unsigned char IDLength; /* length of Identifier String */
68  unsigned char CoMapType; /* 0 = no map */
69  unsigned char ImgType; /* image type (see below for values) */
70  unsigned char Index_lo, Index_hi; /* index of first color map entry */
71  unsigned char Length_lo, Length_hi; /* number of entries in color map */
72  unsigned char CoSize; /* size of color map entry (15,16,24,32) */
73  unsigned char X_org_lo, X_org_hi; /* x origin of image */
74  unsigned char Y_org_lo, Y_org_hi; /* y origin of image */
75  unsigned char Width_lo, Width_hi; /* width of image */
76  unsigned char Height_lo, Height_hi; /* height of image */
77  unsigned char PixelSize; /* pixel size (8,16,24,32) */
78  unsigned char AttBits; /* 4 bits, number of attribute bits per pixel */
79  unsigned char Rsrvd; /* 1 bit, reserved */
80  unsigned char OrgBit; /* 1 bit, origin: 0=lower left, 1=upper left */
81  unsigned char IntrLve; /* 2 bits, interleaving flag */
82  };
83 
84 typedef char ImageIDField[256];
85 
86 /* Max number of colors allowed for colormapped output. */
87 #define TGA_MAXCOLORS 257
88 
89 /* Definitions for image types. */
90 #define TGA_Null 0
91 #define TGA_Map 1
92 #define TGA_RGB 2
93 #define TGA_Mono 3
94 #define TGA_RLEMap 9
95 #define TGA_RLERGB 10
96 #define TGA_RLEMono 11
97 #define TGA_CompMap 32
98 #define TGA_CompMap4 33
99 
100 /* Definitions for interleave flag. */
101 #define TGA_IL_None 0
102 #define TGA_IL_Two 1
103 #define TGA_IL_Four 2
104 
105 ////////////////////////////////////////////////////////////////////
106 // Function: PNMFileTypeTGA::Constructor
107 // Access: Public
108 // Description:
109 ////////////////////////////////////////////////////////////////////
110 PNMFileTypeTGA::
111 PNMFileTypeTGA() {
112 }
113 
114 ////////////////////////////////////////////////////////////////////
115 // Function: PNMFileTypeTGA::get_name
116 // Access: Public, Virtual
117 // Description: Returns a few words describing the file type.
118 ////////////////////////////////////////////////////////////////////
119 string PNMFileTypeTGA::
120 get_name() const {
121  return "Targa";
122 }
123 
124 ////////////////////////////////////////////////////////////////////
125 // Function: PNMFileTypeTGA::get_num_extensions
126 // Access: Public, Virtual
127 // Description: Returns the number of different possible filename
128 // extensions_tga associated with this particular file type.
129 ////////////////////////////////////////////////////////////////////
130 int PNMFileTypeTGA::
131 get_num_extensions() const {
132  return num_extensions_tga;
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: PNMFileTypeTGA::get_extension
137 // Access: Public, Virtual
138 // Description: Returns the nth possible filename extension
139 // associated with this particular file type, without a
140 // leading dot.
141 ////////////////////////////////////////////////////////////////////
142 string PNMFileTypeTGA::
143 get_extension(int n) const {
144  nassertr(n >= 0 && n < num_extensions_tga, string());
145  return extensions_tga[n];
146 }
147 
148 ////////////////////////////////////////////////////////////////////
149 // Function: PNMFileTypeTGA::get_suggested_extension
150 // Access: Public, Virtual
151 // Description: Returns a suitable filename extension (without a
152 // leading dot) to suggest for files of this type, or
153 // empty string if no suggestions are available.
154 ////////////////////////////////////////////////////////////////////
155 string PNMFileTypeTGA::
156 get_suggested_extension() const {
157  return "tga";
158 }
159 
160 ////////////////////////////////////////////////////////////////////
161 // Function: PNMFileTypeTGA::make_reader
162 // Access: Public, Virtual
163 // Description: Allocates and returns a new PNMReader suitable for
164 // reading from this file type, if possible. If reading
165 // from this file type is not supported, returns NULL.
166 ////////////////////////////////////////////////////////////////////
167 PNMReader *PNMFileTypeTGA::
168 make_reader(istream *file, bool owns_file, const string &magic_number) {
169  init_pnm();
170  return new Reader(this, file, owns_file, magic_number);
171 }
172 
173 ////////////////////////////////////////////////////////////////////
174 // Function: PNMFileTypeTGA::make_writer
175 // Access: Public, Virtual
176 // Description: Allocates and returns a new PNMWriter suitable for
177 // reading from this file type, if possible. If writing
178 // files of this type is not supported, returns NULL.
179 ////////////////////////////////////////////////////////////////////
180 PNMWriter *PNMFileTypeTGA::
181 make_writer(ostream *file, bool owns_file) {
182  init_pnm();
183  return new Writer(this, file, owns_file);
184 }
185 
186 
187 ////////////////////////////////////////////////////////////////////
188 // Function: PNMFileTypeTGA::Reader::Constructor
189 // Access: Public
190 // Description:
191 ////////////////////////////////////////////////////////////////////
192 PNMFileTypeTGA::Reader::
193 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
194  PNMReader(type, file, owns_file)
195 {
196  tga_head = new ImageHeader;
197  RLE_count = 0;
198  RLE_flag = 0;
199  ColorMap = NULL;
200  AlphaMap = NULL;
201 
202  Red = 0;
203  Grn = 0;
204  Blu = 0;
205  Alpha = 0;
206  l = 0;
207 
208  /* Read the Targa file header. */
209  readtga( file, tga_head, magic_number );
210  /*
211  {
212  pm_message( "IDLength = %d", (int) tga_head->IDLength );
213  pm_message( "CoMapType = %d", (int) tga_head->CoMapType );
214  pm_message( "ImgType = %d", (int) tga_head->ImgType );
215  pm_message( "Index_lo = %d", (int) tga_head->Index_lo );
216  pm_message( "Index_hi = %d", (int) tga_head->Index_hi );
217  pm_message( "Length_lo = %d", (int) tga_head->Length_lo );
218  pm_message( "Length_hi = %d", (int) tga_head->Length_hi );
219  pm_message( "CoSize = %d", (int) tga_head->CoSize );
220  pm_message( "X_org_lo = %d", (int) tga_head->X_org_lo );
221  pm_message( "X_org_hi = %d", (int) tga_head->X_org_hi );
222  pm_message( "Y_org_lo = %d", (int) tga_head->Y_org_lo );
223  pm_message( "Y_org_hi = %d", (int) tga_head->Y_org_hi );
224  pm_message( "Width_lo = %d", (int) tga_head->Width_lo );
225  pm_message( "Width_hi = %d", (int) tga_head->Width_hi );
226  pm_message( "Height_lo = %d", (int) tga_head->Height_lo );
227  pm_message( "Height_hi = %d", (int) tga_head->Height_hi );
228  pm_message( "PixelSize = %d", (int) tga_head->PixelSize );
229  pm_message( "AttBits = %d", (int) tga_head->AttBits );
230  pm_message( "Rsrvd = %d", (int) tga_head->Rsrvd );
231  pm_message( "OrgBit = %d", (int) tga_head->OrgBit );
232  pm_message( "IntrLve = %d", (int) tga_head->IntrLve );
233  }
234  */
235  rows = ( (int) tga_head->Height_lo ) + ( (int) tga_head->Height_hi ) * 256;
236  cols = ( (int) tga_head->Width_lo ) + ( (int) tga_head->Width_hi ) * 256;
237 
238  switch ( tga_head->ImgType )
239  {
240  case TGA_Map:
241  case TGA_RGB:
242  case TGA_Mono:
243  case TGA_RLEMap:
244  case TGA_RLERGB:
245  case TGA_RLEMono:
246  break;
247 
248  default:
249  pm_error( "unknown Targa image type %d", tga_head->ImgType );
250  }
251 
252  int size;
253 
254  if ( tga_head->ImgType == TGA_Map ||
255  tga_head->ImgType == TGA_RLEMap ||
256  tga_head->ImgType == TGA_CompMap ||
257  tga_head->ImgType == TGA_CompMap4 )
258  { /* Color-mapped image */
259  if ( tga_head->CoMapType != 1 )
260  pm_error(
261  "mapped image (type %d) with color map type != 1",
262  tga_head->ImgType );
263  mapped = 1;
264  /* Figure maxval from CoSize. */
265  size = tga_head->CoSize;
266  }
267  else
268  { /* Not colormap, so figure maxval from PixelSize. */
269  mapped = 0;
270  size = tga_head->PixelSize;
271  }
272 
273  switch ( size ) {
274  case 8:
275  _num_channels = 1;
276  _maxval = 255;
277  break;
278 
279  case 24:
280  _num_channels = 3;
281  _maxval = 255;
282  break;
283 
284  case 32:
285  _num_channels = 4;
286  _maxval = 255;
287  break;
288 
289  case 15:
290  case 16:
291  _num_channels = 3;
292  _maxval = 31;
293  break;
294 
295  default:
296  pm_error("unknown pixel size - %d", size );
297  }
298 
299  /* If required, read the color map information. */
300  if ( tga_head->CoMapType != 0 )
301  {
302  unsigned int temp1, temp2;
303  temp1 = tga_head->Index_lo + tga_head->Index_hi * 256;
304  temp2 = tga_head->Length_lo + tga_head->Length_hi * 256;
305  int num_colors = temp1 + temp2 + 1;
306  nassertv(ColorMap == NULL && AlphaMap == NULL);
307  ColorMap = (pixel *)PANDA_MALLOC_ARRAY(num_colors * sizeof(pixel));
308  AlphaMap = (gray *)PANDA_MALLOC_ARRAY(num_colors * sizeof(gray));
309  for ( unsigned int i = temp1; i < ( temp1 + temp2 ); ++i )
310  get_map_entry( file, &ColorMap[i], (int) tga_head->CoSize,
311  &AlphaMap[i]);
312  }
313 
314  /* Check run-length encoding. */
315  if ( tga_head->ImgType == TGA_RLEMap ||
316  tga_head->ImgType == TGA_RLERGB ||
317  tga_head->ImgType == TGA_RLEMono )
318  rlencoded = 1;
319  else
320  rlencoded = 0;
321 
322  _x_size = cols;
323  _y_size = rows;
324  //_num_channels = 3;
325 
326 }
327 
328 ////////////////////////////////////////////////////////////////////
329 // Function: PNMFileTypeTGA::Reader::Destructor
330 // Access: Public, Virtual
331 // Description:
332 ////////////////////////////////////////////////////////////////////
333 PNMFileTypeTGA::Reader::
334 ~Reader() {
335  delete tga_head;
336  if (ColorMap != NULL) {
337  PANDA_FREE_ARRAY(ColorMap);
338  }
339  if (AlphaMap != NULL) {
340  PANDA_FREE_ARRAY(AlphaMap);
341  }
342 }
343 
344 ////////////////////////////////////////////////////////////////////
345 // Function: PNMFileTypeTGA::Reader::read_data
346 // Access: Public, Virtual
347 // Description: Reads in an entire image all at once, storing it in
348 // the pre-allocated _x_size * _y_size array and alpha
349 // pointers. (If the image type has no alpha channel,
350 // alpha is ignored.) Returns the number of rows
351 // correctly read.
352 //
353 // Derived classes need not override this if they
354 // instead provide supports_read_row() and read_row(),
355 // below.
356 ////////////////////////////////////////////////////////////////////
357 int PNMFileTypeTGA::Reader::
358 read_data(xel *array, xelval *alpha) {
359  int truerow = 0;
360  int baserow = 0;
361  for ( int row = 0; row < rows; ++row )
362  {
363  int realrow = truerow;
364  if ( tga_head->OrgBit == 0 )
365  realrow = rows - realrow - 1;
366 
367  for ( int col = 0; col < cols; ++col )
368  get_pixel( _file, &(array[realrow * cols + col]),
369  (int) tga_head->PixelSize,
370  &(alpha[realrow * cols + col]) );
371  if ( tga_head->IntrLve == TGA_IL_Four )
372  truerow += 4;
373  else if ( tga_head->IntrLve == TGA_IL_Two )
374  truerow += 2;
375  else
376  ++truerow;
377  if ( truerow >= rows )
378  truerow = ++baserow;
379  }
380 
381  return rows;
382 }
383 
384 ////////////////////////////////////////////////////////////////////
385 // Function: PNMFileTypeTGA::Writer::Constructor
386 // Access: Public
387 // Description:
388 ////////////////////////////////////////////////////////////////////
389 PNMFileTypeTGA::Writer::
390 Writer(PNMFileType *type, ostream *file, bool owns_file) :
391  PNMWriter(type, file, owns_file)
392 {
393  tgaHeader = new ImageHeader;
394  chv = (colorhist_vector)0;
395  cht = (colorhash_table)0;
396  runlength = (int*)0;
397 }
398 
399 ////////////////////////////////////////////////////////////////////
400 // Function: PNMFileTypeTGA::Writer::Destructor
401 // Access: Public
402 // Description:
403 ////////////////////////////////////////////////////////////////////
404 PNMFileTypeTGA::Writer::
405 ~Writer() {
406  delete tgaHeader;
407 
408  if (chv != (colorhist_vector)0) {
409  ppm_freecolorhist(chv);
410  }
411  if (cht != (colorhash_table)0) {
412  ppm_freecolorhash(cht);
413  }
414  if (runlength != (int *)0) {
415  pm_freerow((char *)runlength);
416  }
417 }
418 
419 ////////////////////////////////////////////////////////////////////
420 // Function: PNMFileTypeBMP::Writer::write_data
421 // Access: Public, Virtual
422 // Description: Writes out an entire image all at once, including the
423 // header, based on the image data stored in the given
424 // _x_size * _y_size array and alpha pointers. (If the
425 // image type has no alpha channel, alpha is ignored.)
426 // Returns the number of rows correctly written.
427 //
428 // It is the user's responsibility to fill in the header
429 // data via calls to set_x_size(), set_num_channels(),
430 // etc., or copy_header_from(), before calling
431 // write_data().
432 //
433 // It is important to delete the PNMWriter class after
434 // successfully writing the data. Failing to do this
435 // may result in some data not getting flushed!
436 //
437 // Derived classes need not override this if they
438 // instead provide supports_streaming() and write_row(),
439 // below.
440 ////////////////////////////////////////////////////////////////////
441 int PNMFileTypeTGA::Writer::
442 write_data(xel *array, xelval *) {
443  // We don't presently support writing 4-channel tga files (since
444  // ppmtotga doesn't support this).
445  rle_flag = tga_rle;
446 
447  int row, col;
448  int i;
449  pixel* pP;
450 
451  cols = _x_size;
452  rows = _y_size;
453 
454  if (is_grayscale() && tga_grayscale) {
455  // We allow grayscale TGA files, and this is a grayscale image, so...
456  tgaHeader->ImgType = TGA_Mono;
457 
458  // There's no real point in colormapping a grayscale image.
459  pnmimage_tga_cat.info()
460  << "writing grayscale.\n";
461 
462  } else {
463  // This will be an RGB image.
464  tgaHeader->ImgType = TGA_RGB;
465 
466  if (tga_colormap) {
467  // It may even be colormapped if there are few enough colors.
468  pnmimage_tga_cat.info()
469  << "computing colormap...\n";
470  chv = ppm_computecolorhist(&array, cols * rows, 1, TGA_MAXCOLORS, &ncolors );
471  if ( chv == (colorhist_vector) 0 ) {
472  pnmimage_tga_cat.info()
473  << "too many colors, writing RGB.\n";
474  } else {
475  pnmimage_tga_cat.info()
476  << ncolors << " colors found.\n";
477  tgaHeader->ImgType = TGA_Map;
478  }
479  }
480  }
481 
482  if ( rle_flag )
483  {
484  switch ( tgaHeader->ImgType )
485  {
486  case TGA_Mono:
487  tgaHeader->ImgType = TGA_RLEMono;
488  break;
489  case TGA_Map:
490  tgaHeader->ImgType = TGA_RLEMap;
491  break;
492  case TGA_RGB:
493  tgaHeader->ImgType = TGA_RLERGB;
494  break;
495  default:
496  pm_error( "can't happen" );
497  }
498  runlength = (int*) pm_allocrow( cols, sizeof(int) );
499  }
500 
501  tgaHeader->IDLength = 0;
502  tgaHeader->Index_lo = 0;
503  tgaHeader->Index_hi = 0;
504  if ( tgaHeader->ImgType == TGA_Map || tgaHeader->ImgType == TGA_RLEMap )
505  {
506  /* Make a hash table for fast color lookup. */
507  cht = ppm_colorhisttocolorhash( chv, ncolors );
508 
509  tgaHeader->CoMapType = 1;
510  tgaHeader->Length_lo = ncolors % 256;
511  tgaHeader->Length_hi = ncolors / 256;
512  tgaHeader->CoSize = 24;
513  }
514  else
515  {
516  tgaHeader->CoMapType = 0;
517  tgaHeader->Length_lo = 0;
518  tgaHeader->Length_hi = 0;
519  tgaHeader->CoSize = 0;
520  }
521  if ( tgaHeader->ImgType == TGA_RGB || tgaHeader->ImgType == TGA_RLERGB )
522  tgaHeader->PixelSize = 24;
523  else
524  tgaHeader->PixelSize = 8;
525  tgaHeader->X_org_lo = tgaHeader->X_org_hi = 0;
526  tgaHeader->Y_org_lo = tgaHeader->Y_org_hi = 0;
527  tgaHeader->Width_lo = cols % 256;
528  tgaHeader->Width_hi = cols / 256;
529  tgaHeader->Height_lo = rows % 256;
530  tgaHeader->Height_hi = rows / 256;
531  tgaHeader->AttBits = 0;
532  tgaHeader->Rsrvd = 0;
533  tgaHeader->IntrLve = 0;
534  tgaHeader->OrgBit = 0;
535 
536  /* Write out the Targa header. */
537  writetga( tgaHeader, (char*) 0 );
538 
539  if ( tgaHeader->ImgType == TGA_Map || tgaHeader->ImgType == TGA_RLEMap )
540  {
541  /* Write out the Targa colormap. */
542  for ( i = 0; i < ncolors; ++i )
543  put_map_entry( &chv[i].color, tgaHeader->CoSize, _maxval );
544  }
545 
546  /* Write out the pixels */
547  for ( row = 0; row < rows; ++row )
548  {
549  int realrow = row;
550  if ( tgaHeader->OrgBit == 0 )
551  realrow = rows - realrow - 1;
552  if ( rle_flag )
553  {
554  compute_runlengths( cols, &array[realrow * cols], runlength );
555  for ( col = 0; col < cols; )
556  {
557  if ( runlength[col] > 0 )
558  {
559  _file->put( 0x80 + runlength[col] - 1 );
560  put_pixel(&(array[realrow * cols + col]),
561  tgaHeader->ImgType, _maxval, cht );
562  col += runlength[col];
563  }
564  else if ( runlength[col] < 0 )
565  {
566  _file->put( -runlength[col] - 1 );
567  for ( i = 0; i < -runlength[col]; ++i )
568  put_pixel(&(array[realrow * cols + (col + i)]),
569  tgaHeader->ImgType, _maxval, cht );
570  col += -runlength[col];
571  }
572  else
573  pm_error( "can't happen" );
574  }
575  }
576  else
577  {
578  for ( col = 0, pP = &array[realrow * cols]; col < cols; ++col, ++pP )
579  put_pixel( pP, tgaHeader->ImgType, _maxval, cht );
580  }
581  }
582 
583  return rows;
584 }
585 
586 
587 
588 ////////////////////////////////////////////////////////////////////
589 // Function: PNMFileTypeTGA::register_with_read_factory
590 // Access: Public, Static
591 // Description: Registers the current object as something that can be
592 // read from a Bam file.
593 ////////////////////////////////////////////////////////////////////
594 void PNMFileTypeTGA::
595 register_with_read_factory() {
597  register_factory(get_class_type(), make_PNMFileTypeTGA);
598 }
599 
600 ////////////////////////////////////////////////////////////////////
601 // Function: PNMFileTypeTGA::make_PNMFileTypeTGA
602 // Access: Protected, Static
603 // Description: This method is called by the BamReader when an object
604 // of this type is encountered in a Bam file; it should
605 // allocate and return a new object with all the data
606 // read.
607 //
608 // In the case of the PNMFileType objects, since these
609 // objects are all shared, we just pull the object from
610 // the registry.
611 ////////////////////////////////////////////////////////////////////
612 TypedWritable *PNMFileTypeTGA::
613 make_PNMFileTypeTGA(const FactoryParams &params) {
614  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
615 }
616 
617 void PNMFileTypeTGA::Reader::
618 readtga( istream *ifp, struct ImageHeader *tgaP, const string &magic_number ) {
619  unsigned char flags;
620  ImageIDField junk;
621 
622  if (magic_number.length() > 0) {
623  tgaP->IDLength = (unsigned char)magic_number[0];
624  } else {
625  tgaP->IDLength = getbyte( ifp );
626  }
627  if (magic_number.length() > 1) {
628  tgaP->CoMapType = (unsigned char)magic_number[1];
629  } else {
630  tgaP->CoMapType = getbyte( ifp );
631  }
632  if (magic_number.length() > 2) {
633  tgaP->ImgType = (unsigned char)magic_number[2];
634  } else {
635  tgaP->ImgType = getbyte( ifp );
636  }
637  if (magic_number.length() > 3) {
638  tgaP->Index_lo = (unsigned char)magic_number[3];
639  } else {
640  tgaP->Index_lo = getbyte( ifp );
641  }
642  tgaP->Index_hi = getbyte( ifp );
643  tgaP->Length_lo = getbyte( ifp );
644  tgaP->Length_hi = getbyte( ifp );
645  tgaP->CoSize = getbyte( ifp );
646  tgaP->X_org_lo = getbyte( ifp );
647  tgaP->X_org_hi = getbyte( ifp );
648  tgaP->Y_org_lo = getbyte( ifp );
649  tgaP->Y_org_hi = getbyte( ifp );
650  tgaP->Width_lo = getbyte( ifp );
651  tgaP->Width_hi = getbyte( ifp );
652  tgaP->Height_lo = getbyte( ifp );
653  tgaP->Height_hi = getbyte( ifp );
654  tgaP->PixelSize = getbyte( ifp );
655  flags = getbyte( ifp );
656  tgaP->AttBits = flags & 0xf;
657  tgaP->Rsrvd = ( flags & 0x10 ) >> 4;
658  tgaP->OrgBit = ( flags & 0x20 ) >> 5;
659  tgaP->IntrLve = ( flags & 0xc0 ) >> 6;
660 
661  if ( tgaP->IDLength != 0 )
662  ifp->read(junk, (int) tgaP->IDLength);
663  }
664 
665 void PNMFileTypeTGA::Reader::
666 get_map_entry( istream *ifp, pixel *Value, int Size, gray *Alpha ) {
667  unsigned char j, k;
668  unsigned char r = 0, g = 0, b = 0, a = 0;
669 
670  /* Read appropriate number of bytes, break into rgb & put in map. */
671  switch ( Size )
672  {
673  case 8: /* Grey scale, read and triplicate. */
674  r = g = b = getbyte( ifp );
675  a = 0;
676  break;
677 
678  case 16: /* 5 bits each of red green and blue. */
679  case 15: /* Watch for byte order. */
680  j = getbyte( ifp );
681  k = getbyte( ifp );
682  r = ( k & 0x7C ) >> 2;
683  g = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 );
684  b = j & 0x1F;
685  a = 0;
686  break;
687 
688  case 32: /* 8 bits each of blue, green, red, and alpha */
689  case 24: /* 8 bits each of blue green and red. */
690  b = getbyte( ifp );
691  g = getbyte( ifp );
692  r = getbyte( ifp );
693  if ( Size == 32 )
694  a = getbyte( ifp );
695  else
696  a = 0;
697  break;
698 
699  default:
700  pm_error( "unknown colormap pixel size (#2) - %d", Size );
701  }
702  PPM_ASSIGN( *Value, r, g, b );
703  *Alpha = a;
704 }
705 
706 
707 
708 void PNMFileTypeTGA::Reader::
709 get_pixel( istream *ifp, pixel *dest, int Size, gray *alpha_p) {
710  unsigned char j, k;
711 
712  /* Check if run length encoded. */
713  if ( rlencoded )
714  {
715  if ( RLE_count == 0 )
716  { /* Have to restart run. */
717  unsigned char i;
718  i = getbyte( ifp );
719  RLE_flag = ( i & 0x80 );
720  if ( RLE_flag == 0 )
721  /* Stream of unencoded pixels. */
722  RLE_count = i + 1;
723  else
724  /* Single pixel replicated. */
725  RLE_count = i - 127;
726  /* Decrement count & get pixel. */
727  --RLE_count;
728  }
729  else
730  { /* Have already read count & (at least) first pixel. */
731  --RLE_count;
732  if ( RLE_flag != 0 )
733  /* Replicated pixels. */
734  goto PixEncode;
735  }
736  }
737  /* Read appropriate number of bytes, break into RGB. */
738  switch ( Size )
739  {
740  case 8: /* Grey scale, read and triplicate. */
741  Red = Grn = Blu = l = getbyte( ifp );
742  Alpha = 0;
743  break;
744 
745  case 16: /* 5 bits each of red green and blue. */
746  case 15: /* Watch byte order. */
747  j = getbyte( ifp );
748  k = getbyte( ifp );
749  l = ( (unsigned int) k << 8 ) + j;
750  Red = ( k & 0x7C ) >> 2;
751  Grn = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 );
752  Blu = j & 0x1F;
753  Alpha = 0;
754  break;
755 
756  case 32: /* 8 bits each of blue, green, red, and alpha */
757  case 24: /* 8 bits each of blue, green, and red. */
758  Blu = getbyte( ifp );
759  Grn = getbyte( ifp );
760  Red = getbyte( ifp );
761  if ( Size == 32 )
762  Alpha = getbyte( ifp );
763  else
764  Alpha = 0;
765  l = 0;
766  break;
767 
768  default:
769  pm_error( "unknown pixel size (#2) - %d", Size );
770  }
771 
772 PixEncode:
773  if ( mapped ) {
774  *dest = ColorMap[l];
775  if (has_alpha()) {
776  *alpha_p = AlphaMap[l];
777  }
778  } else {
779  PPM_ASSIGN( *dest, Red, Grn, Blu );
780  if (has_alpha()) {
781  *alpha_p = Alpha;
782  }
783  }
784  }
785 
786 
787 unsigned char PNMFileTypeTGA::Reader::
788 getbyte( istream *ifp ) {
789  unsigned char c;
790 
791  c = ifp->get();
792  if (ifp->fail() || ifp->eof())
793  pm_error( "EOF / read error" );
794 
795  return c;
796  }
797 
798 void PNMFileTypeTGA::Writer::
799 writetga( struct ImageHeader *tgaP, char *id )
800  {
801  unsigned char flags;
802 
803  _file->put( tgaP->IDLength );
804  _file->put( tgaP->CoMapType );
805  _file->put( tgaP->ImgType );
806  _file->put( tgaP->Index_lo );
807  _file->put( tgaP->Index_hi );
808  _file->put( tgaP->Length_lo );
809  _file->put( tgaP->Length_hi );
810  _file->put( tgaP->CoSize );
811  _file->put( tgaP->X_org_lo );
812  _file->put( tgaP->X_org_hi );
813  _file->put( tgaP->Y_org_lo );
814  _file->put( tgaP->Y_org_hi );
815  _file->put( tgaP->Width_lo );
816  _file->put( tgaP->Width_hi );
817  _file->put( tgaP->Height_lo );
818  _file->put( tgaP->Height_hi );
819  _file->put( tgaP->PixelSize );
820  flags = ( tgaP->AttBits & 0xf ) | ( ( tgaP->Rsrvd & 0x1 ) << 4 ) |
821  ( ( tgaP->OrgBit & 0x1 ) << 5 ) | ( ( tgaP->OrgBit & 0x3 ) << 6 );
822  _file->put( flags );
823  if ( tgaP->IDLength )
824  _file->write( id, (int) tgaP->IDLength );
825  }
826 
827 void PNMFileTypeTGA::Writer::
828 put_map_entry( pixel* valueP, int size, pixval maxval )
829  {
830  int j;
831  pixel p;
832 
833  switch ( size )
834  {
835  case 8: /* Grey scale. */
836  put_mono( valueP, maxval );
837  break;
838 
839  case 16: /* 5 bits each of red green and blue. */
840  case 15: /* Watch for byte order. */
841  PPM_DEPTH( p, *valueP, maxval, 31 );
842  j = (int) PPM_GETB( p ) | ( (int) PPM_GETG( p ) << 5 ) |
843  ( (int) PPM_GETR( p ) << 10 );
844  _file->put( j % 256 );
845  _file->put( j / 256 );
846  break;
847 
848  case 32:
849  case 24: /* 8 bits each of blue green and red. */
850  put_rgb( valueP, maxval );
851  break;
852 
853  default:
854  pm_error( "unknown colormap pixel size (#2) - %d", size );
855  }
856  }
857 
858 void PNMFileTypeTGA::Writer::
859 compute_runlengths( int cols, pixel *pixelrow, int *runlength )
860  {
861  int col, start;
862 
863  /* Initialize all run lengths to 0. (This is just an error check.) */
864  for ( col = 0; col < cols; ++col )
865  runlength[col] = 0;
866 
867  /* Find runs of identical pixels. */
868  for ( col = 0; col < cols; )
869  {
870  start = col;
871  do {
872  ++col;
873  }
874  while ( col < cols &&
875  col - start < 128 &&
876  PPM_EQUAL( pixelrow[col], pixelrow[start] ) );
877  runlength[start] = col - start;
878  }
879 
880  /* Now look for runs of length-1 runs, and turn them into negative runs. */
881  for ( col = 0; col < cols; )
882  {
883  if ( runlength[col] == 1 )
884  {
885  start = col;
886  while ( col < cols &&
887  col - start < 128 &&
888  runlength[col] == 1 )
889  {
890  runlength[col] = 0;
891  ++col;
892  }
893  runlength[start] = - ( col - start );
894  }
895  else
896  col += runlength[col];
897  }
898  }
899 
900 void PNMFileTypeTGA::Writer::
901 put_pixel( pixel* pP, int imgtype, pixval maxval, colorhash_table cht )
902  {
903  switch ( imgtype )
904  {
905  case TGA_Mono:
906  case TGA_RLEMono:
907  put_mono( pP, maxval );
908  break;
909  case TGA_Map:
910  case TGA_RLEMap:
911  put_map( pP, cht );
912  break;
913  case TGA_RGB:
914  case TGA_RLERGB:
915  put_rgb( pP, maxval );
916  break;
917  default:
918  pm_error( "can't happen" );
919  }
920  }
921 
922 void PNMFileTypeTGA::Writer::
923 put_mono( pixel* pP, pixval maxval )
924  {
925  pixel p;
926  PPM_DEPTH( p, *pP, maxval, (pixval) 255 );
927  _file->put( PPM_GETB( p ) );
928  }
929 
930 void PNMFileTypeTGA::Writer::
931 put_map( pixel *pP, colorhash_table cht )
932  {
933  _file->put( ppm_lookupcolor( cht, pP ) );
934  }
935 
936 void PNMFileTypeTGA::Writer::
937 put_rgb( pixel* pP, pixval maxval ) {
938  pixel p;
939  PPM_DEPTH( p, *pP, maxval, (pixval) 255 );
940  _file->put( PPM_GETB( p ) );
941  if (is_grayscale()) {
942  _file->put( PPM_GETB( p ) );
943  _file->put( PPM_GETB( p ) );
944  } else {
945  _file->put( PPM_GETG( p ) );
946  _file->put( PPM_GETR( p ) );
947  }
948 }
949 
950 #endif // HAVE_TGA
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:35
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e...
This is an abstract base class that defines the interface for reading image files of various types...
Definition: pnmReader.h:31
This is an abstract base class that defines the interface for writing image files of various types...
Definition: pnmWriter.h:31
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
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:85
bool is_grayscale() const
Returns false if the image is a full-color image, and has red, green, and blue components; true if it...