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