|
|
|
|
@ -0,0 +1,918 @@
|
|
|
|
|
// Filename: pnmFileTypeTGA.cxx
|
|
|
|
|
// Created by: drose (27Apr01)
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Much code in this file is borrowed from Netpbm, specifically tgatoppm.c
|
|
|
|
|
// and ppmtotga.c.
|
|
|
|
|
|
|
|
|
|
/* tgatoppm.c - read a TrueVision Targa file and write a portable pixmap
|
|
|
|
|
**
|
|
|
|
|
** Partially based on tga2rast, version 1.0, by Ian MacPhedran.
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 1989 by Jef Poskanzer.
|
|
|
|
|
**
|
|
|
|
|
** Permission to use, copy, modify, and distribute this software and its
|
|
|
|
|
** documentation for any purpose and without fee is hereby granted, provided
|
|
|
|
|
** that the above copyright notice appear in all copies and that both that
|
|
|
|
|
** copyright notice and this permission notice appear in supporting
|
|
|
|
|
** documentation. This software is provided "as is" without express or
|
|
|
|
|
** implied warranty.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ppmtotga.c - read a portable pixmap and produce a TrueVision Targa file
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 1989, 1991 by Mark Shand and Jef Poskanzer
|
|
|
|
|
**
|
|
|
|
|
** Permission to use, copy, modify, and distribute this software and its
|
|
|
|
|
** documentation for any purpose and without fee is hereby granted, provided
|
|
|
|
|
** that the above copyright notice appear in all copies and that both that
|
|
|
|
|
** copyright notice and this permission notice appear in supporting
|
|
|
|
|
** documentation. This software is provided "as is" without express or
|
|
|
|
|
** implied warranty.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "pnmFileTypeTGA.h"
|
|
|
|
|
#include "config_pnmimagetypes.h"
|
|
|
|
|
|
|
|
|
|
#include <pnmFileTypeRegistry.h>
|
|
|
|
|
#include <bamReader.h>
|
|
|
|
|
|
|
|
|
|
#include <ppm.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
static const char * const extensions[] = {
|
|
|
|
|
"tga"
|
|
|
|
|
};
|
|
|
|
|
static const int num_extensions = sizeof(extensions) / sizeof(const char *);
|
|
|
|
|
|
|
|
|
|
TypeHandle PNMFileTypeTGA::_type_handle;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Header definition. */
|
|
|
|
|
struct ImageHeader {
|
|
|
|
|
unsigned char IDLength; /* length of Identifier String */
|
|
|
|
|
unsigned char CoMapType; /* 0 = no map */
|
|
|
|
|
unsigned char ImgType; /* image type (see below for values) */
|
|
|
|
|
unsigned char Index_lo, Index_hi; /* index of first color map entry */
|
|
|
|
|
unsigned char Length_lo, Length_hi; /* number of entries in color map */
|
|
|
|
|
unsigned char CoSize; /* size of color map entry (15,16,24,32) */
|
|
|
|
|
unsigned char X_org_lo, X_org_hi; /* x origin of image */
|
|
|
|
|
unsigned char Y_org_lo, Y_org_hi; /* y origin of image */
|
|
|
|
|
unsigned char Width_lo, Width_hi; /* width of image */
|
|
|
|
|
unsigned char Height_lo, Height_hi; /* height of image */
|
|
|
|
|
unsigned char PixelSize; /* pixel size (8,16,24,32) */
|
|
|
|
|
unsigned char AttBits; /* 4 bits, number of attribute bits per pixel */
|
|
|
|
|
unsigned char Rsrvd; /* 1 bit, reserved */
|
|
|
|
|
unsigned char OrgBit; /* 1 bit, origin: 0=lower left, 1=upper left */
|
|
|
|
|
unsigned char IntrLve; /* 2 bits, interleaving flag */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef char ImageIDField[256];
|
|
|
|
|
|
|
|
|
|
/* Definitions for image types. */
|
|
|
|
|
#define TGA_Null 0
|
|
|
|
|
#define TGA_Map 1
|
|
|
|
|
#define TGA_RGB 2
|
|
|
|
|
#define TGA_Mono 3
|
|
|
|
|
#define TGA_RLEMap 9
|
|
|
|
|
#define TGA_RLERGB 10
|
|
|
|
|
#define TGA_RLEMono 11
|
|
|
|
|
#define TGA_CompMap 32
|
|
|
|
|
#define TGA_CompMap4 33
|
|
|
|
|
|
|
|
|
|
/* Definitions for interleave flag. */
|
|
|
|
|
#define TGA_IL_None 0
|
|
|
|
|
#define TGA_IL_Two 1
|
|
|
|
|
#define TGA_IL_Four 2
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::Constructor
|
|
|
|
|
// Access: Public
|
|
|
|
|
// Description:
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
PNMFileTypeTGA::
|
|
|
|
|
PNMFileTypeTGA() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::get_name
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description: Returns a few words describing the file type.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
string PNMFileTypeTGA::
|
|
|
|
|
get_name() const {
|
|
|
|
|
return "Targa";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::get_num_extensions
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description: Returns the number of different possible filename
|
|
|
|
|
// extensions associated with this particular file type.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
int PNMFileTypeTGA::
|
|
|
|
|
get_num_extensions() const {
|
|
|
|
|
return num_extensions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::get_extension
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description: Returns the nth possible filename extension
|
|
|
|
|
// associated with this particular file type, without a
|
|
|
|
|
// leading dot.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
string PNMFileTypeTGA::
|
|
|
|
|
get_extension(int n) const {
|
|
|
|
|
nassertr(n >= 0 && n < num_extensions, string());
|
|
|
|
|
return extensions[n];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::get_suggested_extension
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description: Returns a suitable filename extension (without a
|
|
|
|
|
// leading dot) to suggest for files of this type, or
|
|
|
|
|
// empty string if no suggestions are available.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
string PNMFileTypeTGA::
|
|
|
|
|
get_suggested_extension() const {
|
|
|
|
|
return "tga";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::make_reader
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description: Allocates and returns a new PNMReader suitable for
|
|
|
|
|
// reading from this file type, if possible. If reading
|
|
|
|
|
// from this file type is not supported, returns NULL.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
PNMReader *PNMFileTypeTGA::
|
|
|
|
|
make_reader(FILE *file, bool owns_file, const string &magic_number) {
|
|
|
|
|
init_pnm();
|
|
|
|
|
return new Reader(this, file, owns_file, magic_number);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::make_writer
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description: Allocates and returns a new PNMWriter suitable for
|
|
|
|
|
// reading from this file type, if possible. If writing
|
|
|
|
|
// files of this type is not supported, returns NULL.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
PNMWriter *PNMFileTypeTGA::
|
|
|
|
|
make_writer(FILE *file, bool owns_file) {
|
|
|
|
|
init_pnm();
|
|
|
|
|
return new Writer(this, file, owns_file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::Reader::Constructor
|
|
|
|
|
// Access: Public
|
|
|
|
|
// Description:
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
PNMFileTypeTGA::Reader::
|
|
|
|
|
Reader(PNMFileType *type, FILE *file, bool owns_file, string magic_number) :
|
|
|
|
|
PNMReader(type, file, owns_file)
|
|
|
|
|
{
|
|
|
|
|
tga_head = new ImageHeader;
|
|
|
|
|
RLE_count = 0;
|
|
|
|
|
RLE_flag = 0;
|
|
|
|
|
|
|
|
|
|
/* Read the Targa file header. */
|
|
|
|
|
readtga( file, tga_head, magic_number );
|
|
|
|
|
/*
|
|
|
|
|
{
|
|
|
|
|
pm_message( "IDLength = %d", (int) tga_head->IDLength );
|
|
|
|
|
pm_message( "CoMapType = %d", (int) tga_head->CoMapType );
|
|
|
|
|
pm_message( "ImgType = %d", (int) tga_head->ImgType );
|
|
|
|
|
pm_message( "Index_lo = %d", (int) tga_head->Index_lo );
|
|
|
|
|
pm_message( "Index_hi = %d", (int) tga_head->Index_hi );
|
|
|
|
|
pm_message( "Length_lo = %d", (int) tga_head->Length_lo );
|
|
|
|
|
pm_message( "Length_hi = %d", (int) tga_head->Length_hi );
|
|
|
|
|
pm_message( "CoSize = %d", (int) tga_head->CoSize );
|
|
|
|
|
pm_message( "X_org_lo = %d", (int) tga_head->X_org_lo );
|
|
|
|
|
pm_message( "X_org_hi = %d", (int) tga_head->X_org_hi );
|
|
|
|
|
pm_message( "Y_org_lo = %d", (int) tga_head->Y_org_lo );
|
|
|
|
|
pm_message( "Y_org_hi = %d", (int) tga_head->Y_org_hi );
|
|
|
|
|
pm_message( "Width_lo = %d", (int) tga_head->Width_lo );
|
|
|
|
|
pm_message( "Width_hi = %d", (int) tga_head->Width_hi );
|
|
|
|
|
pm_message( "Height_lo = %d", (int) tga_head->Height_lo );
|
|
|
|
|
pm_message( "Height_hi = %d", (int) tga_head->Height_hi );
|
|
|
|
|
pm_message( "PixelSize = %d", (int) tga_head->PixelSize );
|
|
|
|
|
pm_message( "AttBits = %d", (int) tga_head->AttBits );
|
|
|
|
|
pm_message( "Rsrvd = %d", (int) tga_head->Rsrvd );
|
|
|
|
|
pm_message( "OrgBit = %d", (int) tga_head->OrgBit );
|
|
|
|
|
pm_message( "IntrLve = %d", (int) tga_head->IntrLve );
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
rows = ( (int) tga_head->Height_lo ) + ( (int) tga_head->Height_hi ) * 256;
|
|
|
|
|
cols = ( (int) tga_head->Width_lo ) + ( (int) tga_head->Width_hi ) * 256;
|
|
|
|
|
|
|
|
|
|
switch ( tga_head->ImgType )
|
|
|
|
|
{
|
|
|
|
|
case TGA_Map:
|
|
|
|
|
case TGA_RGB:
|
|
|
|
|
case TGA_Mono:
|
|
|
|
|
case TGA_RLEMap:
|
|
|
|
|
case TGA_RLERGB:
|
|
|
|
|
case TGA_RLEMono:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
pm_error( "unknown Targa image type %d", tga_head->ImgType );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int size;
|
|
|
|
|
|
|
|
|
|
if ( tga_head->ImgType == TGA_Map ||
|
|
|
|
|
tga_head->ImgType == TGA_RLEMap ||
|
|
|
|
|
tga_head->ImgType == TGA_CompMap ||
|
|
|
|
|
tga_head->ImgType == TGA_CompMap4 )
|
|
|
|
|
{ /* Color-mapped image */
|
|
|
|
|
if ( tga_head->CoMapType != 1 )
|
|
|
|
|
pm_error(
|
|
|
|
|
"mapped image (type %d) with color map type != 1",
|
|
|
|
|
tga_head->ImgType );
|
|
|
|
|
mapped = 1;
|
|
|
|
|
/* Figure maxval from CoSize. */
|
|
|
|
|
size = tga_head->CoSize;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /* Not colormap, so figure maxval from PixelSize. */
|
|
|
|
|
mapped = 0;
|
|
|
|
|
size = tga_head->PixelSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch ( size ) {
|
|
|
|
|
case 8:
|
|
|
|
|
_num_channels = 1;
|
|
|
|
|
_maxval = 255;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 24:
|
|
|
|
|
_num_channels = 3;
|
|
|
|
|
_maxval = 255;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
|
_num_channels = 4;
|
|
|
|
|
_maxval = 255;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 15:
|
|
|
|
|
case 16:
|
|
|
|
|
_num_channels = 3;
|
|
|
|
|
_maxval = 31;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
pm_error("unknown pixel size - %d", size );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If required, read the color map information. */
|
|
|
|
|
if ( tga_head->CoMapType != 0 )
|
|
|
|
|
{
|
|
|
|
|
unsigned int temp1, temp2;
|
|
|
|
|
temp1 = tga_head->Index_lo + tga_head->Index_hi * 256;
|
|
|
|
|
temp2 = tga_head->Length_lo + tga_head->Length_hi * 256;
|
|
|
|
|
if ( ( temp1 + temp2 + 1 ) >= TGA_MAXCOLORS )
|
|
|
|
|
pm_error( "too many colors - %d", ( temp1 + temp2 + 1 ) );
|
|
|
|
|
for ( unsigned int i = temp1; i < ( temp1 + temp2 ); ++i )
|
|
|
|
|
get_map_entry( file, &ColorMap[i], (int) tga_head->CoSize,
|
|
|
|
|
&AlphaMap[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check run-length encoding. */
|
|
|
|
|
if ( tga_head->ImgType == TGA_RLEMap ||
|
|
|
|
|
tga_head->ImgType == TGA_RLERGB ||
|
|
|
|
|
tga_head->ImgType == TGA_RLEMono )
|
|
|
|
|
rlencoded = 1;
|
|
|
|
|
else
|
|
|
|
|
rlencoded = 0;
|
|
|
|
|
|
|
|
|
|
_x_size = cols;
|
|
|
|
|
_y_size = rows;
|
|
|
|
|
_num_channels = 3;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::Reader::Destructor
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description:
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
PNMFileTypeTGA::Reader::
|
|
|
|
|
~Reader() {
|
|
|
|
|
delete tga_head;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::Reader::read_data
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description: Reads in an entire image all at once, storing it in
|
|
|
|
|
// the pre-allocated _x_size * _y_size array and alpha
|
|
|
|
|
// pointers. (If the image type has no alpha channel,
|
|
|
|
|
// alpha is ignored.) Returns the number of rows
|
|
|
|
|
// correctly read.
|
|
|
|
|
//
|
|
|
|
|
// Derived classes need not override this if they
|
|
|
|
|
// instead provide supports_read_row() and read_row(),
|
|
|
|
|
// below.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
int PNMFileTypeTGA::Reader::
|
|
|
|
|
read_data(xel *array, xelval *alpha) {
|
|
|
|
|
int truerow = 0;
|
|
|
|
|
int baserow = 0;
|
|
|
|
|
for ( int row = 0; row < rows; ++row )
|
|
|
|
|
{
|
|
|
|
|
int realrow = truerow;
|
|
|
|
|
if ( tga_head->OrgBit == 0 )
|
|
|
|
|
realrow = rows - realrow - 1;
|
|
|
|
|
|
|
|
|
|
for ( int col = 0; col < cols; ++col )
|
|
|
|
|
get_pixel( _file, &(array[realrow * cols + col]),
|
|
|
|
|
(int) tga_head->PixelSize,
|
|
|
|
|
&(alpha[realrow * cols + col]) );
|
|
|
|
|
if ( tga_head->IntrLve == TGA_IL_Four )
|
|
|
|
|
truerow += 4;
|
|
|
|
|
else if ( tga_head->IntrLve == TGA_IL_Two )
|
|
|
|
|
truerow += 2;
|
|
|
|
|
else
|
|
|
|
|
++truerow;
|
|
|
|
|
if ( truerow >= rows )
|
|
|
|
|
truerow = ++baserow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::Writer::Constructor
|
|
|
|
|
// Access: Public
|
|
|
|
|
// Description:
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
PNMFileTypeTGA::Writer::
|
|
|
|
|
Writer(PNMFileType *type, FILE *file, bool owns_file) :
|
|
|
|
|
PNMWriter(type, file, owns_file)
|
|
|
|
|
{
|
|
|
|
|
tgaHeader = new ImageHeader;
|
|
|
|
|
chv = (colorhist_vector)0;
|
|
|
|
|
cht = (colorhash_table)0;
|
|
|
|
|
runlength = (int*)0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::Writer::Destructor
|
|
|
|
|
// Access: Public
|
|
|
|
|
// Description:
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
PNMFileTypeTGA::Writer::
|
|
|
|
|
~Writer() {
|
|
|
|
|
delete tgaHeader;
|
|
|
|
|
|
|
|
|
|
if (chv != (colorhist_vector)0) {
|
|
|
|
|
ppm_freecolorhist(chv);
|
|
|
|
|
}
|
|
|
|
|
if (cht != (colorhash_table)0) {
|
|
|
|
|
ppm_freecolorhash(cht);
|
|
|
|
|
}
|
|
|
|
|
if (runlength != (int *)0) {
|
|
|
|
|
pm_freerow((char *)runlength);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeBMP::Writer::write_data
|
|
|
|
|
// Access: Public, Virtual
|
|
|
|
|
// Description: Writes out an entire image all at once, including the
|
|
|
|
|
// header, based on the image data stored in the given
|
|
|
|
|
// _x_size * _y_size array and alpha pointers. (If the
|
|
|
|
|
// image type has no alpha channel, alpha is ignored.)
|
|
|
|
|
// Returns the number of rows correctly written.
|
|
|
|
|
//
|
|
|
|
|
// It is the user's responsibility to fill in the header
|
|
|
|
|
// data via calls to set_x_size(), set_num_channels(),
|
|
|
|
|
// etc., or copy_header_from(), before calling
|
|
|
|
|
// write_data().
|
|
|
|
|
//
|
|
|
|
|
// It is important to delete the PNMWriter class after
|
|
|
|
|
// successfully writing the data. Failing to do this
|
|
|
|
|
// may result in some data not getting flushed!
|
|
|
|
|
//
|
|
|
|
|
// Derived classes need not override this if they
|
|
|
|
|
// instead provide supports_streaming() and write_row(),
|
|
|
|
|
// below.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
int PNMFileTypeTGA::Writer::
|
|
|
|
|
write_data(xel *array, xelval *) {
|
|
|
|
|
// We don't presently support writing 4-channel tga files (since
|
|
|
|
|
// ppmtotga doesn't support this).
|
|
|
|
|
rle_flag = tga_rle;
|
|
|
|
|
|
|
|
|
|
int row, col;
|
|
|
|
|
int i;
|
|
|
|
|
pixel* pP;
|
|
|
|
|
|
|
|
|
|
cols = _x_size;
|
|
|
|
|
rows = _y_size;
|
|
|
|
|
|
|
|
|
|
if (is_grayscale() && tga_grayscale) {
|
|
|
|
|
// We allow grayscale TGA files, and this is a grayscale image, so...
|
|
|
|
|
tgaHeader->ImgType = TGA_Mono;
|
|
|
|
|
|
|
|
|
|
// There's no real point in colormapping a grayscale image.
|
|
|
|
|
pnmimage_tga_cat.info()
|
|
|
|
|
<< "writing grayscale.\n";
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// This will be an RGB image.
|
|
|
|
|
tgaHeader->ImgType = TGA_RGB;
|
|
|
|
|
|
|
|
|
|
if (tga_colormap) {
|
|
|
|
|
// It may even be colormapped if there are few enough colors.
|
|
|
|
|
pnmimage_tga_cat.info()
|
|
|
|
|
<< "computing colormap...\n";
|
|
|
|
|
chv = ppm_computecolorhist(&array, cols * rows, 1, TGA_MAXCOLORS, &ncolors );
|
|
|
|
|
if ( chv == (colorhist_vector) 0 ) {
|
|
|
|
|
pnmimage_tga_cat.info()
|
|
|
|
|
<< "too many colors, writing RGB.\n";
|
|
|
|
|
} else {
|
|
|
|
|
pnmimage_tga_cat.info()
|
|
|
|
|
<< ncolors << " colors found.\n";
|
|
|
|
|
tgaHeader->ImgType = TGA_Map;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( rle_flag )
|
|
|
|
|
{
|
|
|
|
|
switch ( tgaHeader->ImgType )
|
|
|
|
|
{
|
|
|
|
|
case TGA_Mono:
|
|
|
|
|
tgaHeader->ImgType = TGA_RLEMono;
|
|
|
|
|
break;
|
|
|
|
|
case TGA_Map:
|
|
|
|
|
tgaHeader->ImgType = TGA_RLEMap;
|
|
|
|
|
break;
|
|
|
|
|
case TGA_RGB:
|
|
|
|
|
tgaHeader->ImgType = TGA_RLERGB;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
pm_error( "can't happen" );
|
|
|
|
|
}
|
|
|
|
|
runlength = (int*) pm_allocrow( cols, sizeof(int) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tgaHeader->IDLength = 0;
|
|
|
|
|
tgaHeader->Index_lo = 0;
|
|
|
|
|
tgaHeader->Index_hi = 0;
|
|
|
|
|
if ( tgaHeader->ImgType == TGA_Map || tgaHeader->ImgType == TGA_RLEMap )
|
|
|
|
|
{
|
|
|
|
|
/* Make a hash table for fast color lookup. */
|
|
|
|
|
cht = ppm_colorhisttocolorhash( chv, ncolors );
|
|
|
|
|
|
|
|
|
|
tgaHeader->CoMapType = 1;
|
|
|
|
|
tgaHeader->Length_lo = ncolors % 256;
|
|
|
|
|
tgaHeader->Length_hi = ncolors / 256;
|
|
|
|
|
tgaHeader->CoSize = 24;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tgaHeader->CoMapType = 0;
|
|
|
|
|
tgaHeader->Length_lo = 0;
|
|
|
|
|
tgaHeader->Length_hi = 0;
|
|
|
|
|
tgaHeader->CoSize = 0;
|
|
|
|
|
}
|
|
|
|
|
if ( tgaHeader->ImgType == TGA_RGB || tgaHeader->ImgType == TGA_RLERGB )
|
|
|
|
|
tgaHeader->PixelSize = 24;
|
|
|
|
|
else
|
|
|
|
|
tgaHeader->PixelSize = 8;
|
|
|
|
|
tgaHeader->X_org_lo = tgaHeader->X_org_hi = 0;
|
|
|
|
|
tgaHeader->Y_org_lo = tgaHeader->Y_org_hi = 0;
|
|
|
|
|
tgaHeader->Width_lo = cols % 256;
|
|
|
|
|
tgaHeader->Width_hi = cols / 256;
|
|
|
|
|
tgaHeader->Height_lo = rows % 256;
|
|
|
|
|
tgaHeader->Height_hi = rows / 256;
|
|
|
|
|
tgaHeader->AttBits = 0;
|
|
|
|
|
tgaHeader->Rsrvd = 0;
|
|
|
|
|
tgaHeader->IntrLve = 0;
|
|
|
|
|
tgaHeader->OrgBit = 0;
|
|
|
|
|
|
|
|
|
|
/* Write out the Targa header. */
|
|
|
|
|
writetga( tgaHeader, (char*) 0 );
|
|
|
|
|
|
|
|
|
|
if ( tgaHeader->ImgType == TGA_Map || tgaHeader->ImgType == TGA_RLEMap )
|
|
|
|
|
{
|
|
|
|
|
/* Write out the Targa colormap. */
|
|
|
|
|
for ( i = 0; i < ncolors; ++i )
|
|
|
|
|
put_map_entry( &chv[i].color, tgaHeader->CoSize, _maxval );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out the pixels */
|
|
|
|
|
for ( row = 0; row < rows; ++row )
|
|
|
|
|
{
|
|
|
|
|
int realrow = row;
|
|
|
|
|
if ( tgaHeader->OrgBit == 0 )
|
|
|
|
|
realrow = rows - realrow - 1;
|
|
|
|
|
if ( rle_flag )
|
|
|
|
|
{
|
|
|
|
|
compute_runlengths( cols, &array[realrow * cols], runlength );
|
|
|
|
|
for ( col = 0; col < cols; )
|
|
|
|
|
{
|
|
|
|
|
if ( runlength[col] > 0 )
|
|
|
|
|
{
|
|
|
|
|
fputc( 0x80 + runlength[col] - 1, _file );
|
|
|
|
|
put_pixel(&(array[realrow * cols + col]),
|
|
|
|
|
tgaHeader->ImgType, _maxval, cht );
|
|
|
|
|
col += runlength[col];
|
|
|
|
|
}
|
|
|
|
|
else if ( runlength[col] < 0 )
|
|
|
|
|
{
|
|
|
|
|
fputc( -runlength[col] - 1, _file );
|
|
|
|
|
for ( i = 0; i < -runlength[col]; ++i )
|
|
|
|
|
put_pixel(&(array[realrow * cols + (col + i)]),
|
|
|
|
|
tgaHeader->ImgType, _maxval, cht );
|
|
|
|
|
col += -runlength[col];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
pm_error( "can't happen" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for ( col = 0, pP = &array[realrow * cols]; col < cols; ++col, ++pP )
|
|
|
|
|
put_pixel( pP, tgaHeader->ImgType, _maxval, cht );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rows;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::register_with_read_factory
|
|
|
|
|
// Access: Public, Static
|
|
|
|
|
// Description: Registers the current object as something that can be
|
|
|
|
|
// read from a Bam file.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
void PNMFileTypeTGA::
|
|
|
|
|
register_with_read_factory() {
|
|
|
|
|
BamReader::get_factory()->
|
|
|
|
|
register_factory(get_class_type(), make_PNMFileTypeTGA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Function: PNMFileTypeTGA::make_PNMFileTypeTGA
|
|
|
|
|
// Access: Protected, Static
|
|
|
|
|
// Description: This method is called by the BamReader when an object
|
|
|
|
|
// of this type is encountered in a Bam file; it should
|
|
|
|
|
// allocate and return a new object with all the data
|
|
|
|
|
// read.
|
|
|
|
|
//
|
|
|
|
|
// In the case of the PNMFileType objects, since these
|
|
|
|
|
// objects are all shared, we just pull the object from
|
|
|
|
|
// the registry.
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
TypedWriteable *PNMFileTypeTGA::
|
|
|
|
|
make_PNMFileTypeTGA(const FactoryParams ¶ms) {
|
|
|
|
|
return PNMFileTypeRegistry::get_ptr()->get_type_by_handle(get_class_type());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Reader::
|
|
|
|
|
readtga( FILE *ifp, struct ImageHeader *tgaP, const string &magic_number ) {
|
|
|
|
|
unsigned char flags;
|
|
|
|
|
ImageIDField junk;
|
|
|
|
|
|
|
|
|
|
if (magic_number.length() > 0) {
|
|
|
|
|
tgaP->IDLength = (unsigned char)magic_number[0];
|
|
|
|
|
} else {
|
|
|
|
|
tgaP->IDLength = getbyte( ifp );
|
|
|
|
|
}
|
|
|
|
|
if (magic_number.length() > 1) {
|
|
|
|
|
tgaP->CoMapType = (unsigned char)magic_number[1];
|
|
|
|
|
} else {
|
|
|
|
|
tgaP->CoMapType = getbyte( ifp );
|
|
|
|
|
}
|
|
|
|
|
if (magic_number.length() > 2) {
|
|
|
|
|
tgaP->ImgType = (unsigned char)magic_number[2];
|
|
|
|
|
} else {
|
|
|
|
|
tgaP->ImgType = getbyte( ifp );
|
|
|
|
|
}
|
|
|
|
|
if (magic_number.length() > 3) {
|
|
|
|
|
tgaP->Index_lo = (unsigned char)magic_number[3];
|
|
|
|
|
} else {
|
|
|
|
|
tgaP->Index_lo = getbyte( ifp );
|
|
|
|
|
}
|
|
|
|
|
tgaP->Index_hi = getbyte( ifp );
|
|
|
|
|
tgaP->Length_lo = getbyte( ifp );
|
|
|
|
|
tgaP->Length_hi = getbyte( ifp );
|
|
|
|
|
tgaP->CoSize = getbyte( ifp );
|
|
|
|
|
tgaP->X_org_lo = getbyte( ifp );
|
|
|
|
|
tgaP->X_org_hi = getbyte( ifp );
|
|
|
|
|
tgaP->Y_org_lo = getbyte( ifp );
|
|
|
|
|
tgaP->Y_org_hi = getbyte( ifp );
|
|
|
|
|
tgaP->Width_lo = getbyte( ifp );
|
|
|
|
|
tgaP->Width_hi = getbyte( ifp );
|
|
|
|
|
tgaP->Height_lo = getbyte( ifp );
|
|
|
|
|
tgaP->Height_hi = getbyte( ifp );
|
|
|
|
|
tgaP->PixelSize = getbyte( ifp );
|
|
|
|
|
flags = getbyte( ifp );
|
|
|
|
|
tgaP->AttBits = flags & 0xf;
|
|
|
|
|
tgaP->Rsrvd = ( flags & 0x10 ) >> 4;
|
|
|
|
|
tgaP->OrgBit = ( flags & 0x20 ) >> 5;
|
|
|
|
|
tgaP->IntrLve = ( flags & 0xc0 ) >> 6;
|
|
|
|
|
|
|
|
|
|
if ( tgaP->IDLength != 0 )
|
|
|
|
|
fread( junk, 1, (int) tgaP->IDLength, ifp );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Reader::
|
|
|
|
|
get_map_entry( FILE *ifp, pixel *Value, int Size, gray *Alpha ) {
|
|
|
|
|
unsigned char j, k, r, g, b, a;
|
|
|
|
|
|
|
|
|
|
/* Read appropriate number of bytes, break into rgb & put in map. */
|
|
|
|
|
switch ( Size )
|
|
|
|
|
{
|
|
|
|
|
case 8: /* Grey scale, read and triplicate. */
|
|
|
|
|
r = g = b = getbyte( ifp );
|
|
|
|
|
a = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 16: /* 5 bits each of red green and blue. */
|
|
|
|
|
case 15: /* Watch for byte order. */
|
|
|
|
|
j = getbyte( ifp );
|
|
|
|
|
k = getbyte( ifp );
|
|
|
|
|
r = ( k & 0x7C ) >> 2;
|
|
|
|
|
g = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 );
|
|
|
|
|
b = j & 0x1F;
|
|
|
|
|
a = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 32: /* 8 bits each of blue, green, red, and alpha */
|
|
|
|
|
case 24: /* 8 bits each of blue green and red. */
|
|
|
|
|
b = getbyte( ifp );
|
|
|
|
|
g = getbyte( ifp );
|
|
|
|
|
r = getbyte( ifp );
|
|
|
|
|
if ( Size == 32 )
|
|
|
|
|
a = getbyte( ifp );
|
|
|
|
|
else
|
|
|
|
|
a = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
pm_error( "unknown colormap pixel size (#2) - %d", Size );
|
|
|
|
|
}
|
|
|
|
|
PPM_ASSIGN( *Value, r, g, b );
|
|
|
|
|
*Alpha = a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Reader::
|
|
|
|
|
get_pixel( FILE *ifp, pixel *dest, int Size, gray *alpha_p) {
|
|
|
|
|
static pixval Red, Grn, Blu;
|
|
|
|
|
static pixval Alpha;
|
|
|
|
|
unsigned char j, k;
|
|
|
|
|
static unsigned int l;
|
|
|
|
|
|
|
|
|
|
/* Check if run length encoded. */
|
|
|
|
|
if ( rlencoded )
|
|
|
|
|
{
|
|
|
|
|
if ( RLE_count == 0 )
|
|
|
|
|
{ /* Have to restart run. */
|
|
|
|
|
unsigned char i;
|
|
|
|
|
i = getbyte( ifp );
|
|
|
|
|
RLE_flag = ( i & 0x80 );
|
|
|
|
|
if ( RLE_flag == 0 )
|
|
|
|
|
/* Stream of unencoded pixels. */
|
|
|
|
|
RLE_count = i + 1;
|
|
|
|
|
else
|
|
|
|
|
/* Single pixel replicated. */
|
|
|
|
|
RLE_count = i - 127;
|
|
|
|
|
/* Decrement count & get pixel. */
|
|
|
|
|
--RLE_count;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /* Have already read count & (at least) first pixel. */
|
|
|
|
|
--RLE_count;
|
|
|
|
|
if ( RLE_flag != 0 )
|
|
|
|
|
/* Replicated pixels. */
|
|
|
|
|
goto PixEncode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* Read appropriate number of bytes, break into RGB. */
|
|
|
|
|
switch ( Size )
|
|
|
|
|
{
|
|
|
|
|
case 8: /* Grey scale, read and triplicate. */
|
|
|
|
|
Red = Grn = Blu = l = getbyte( ifp );
|
|
|
|
|
Alpha = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 16: /* 5 bits each of red green and blue. */
|
|
|
|
|
case 15: /* Watch byte order. */
|
|
|
|
|
j = getbyte( ifp );
|
|
|
|
|
k = getbyte( ifp );
|
|
|
|
|
l = ( (unsigned int) k << 8 ) + j;
|
|
|
|
|
Red = ( k & 0x7C ) >> 2;
|
|
|
|
|
Grn = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 );
|
|
|
|
|
Blu = j & 0x1F;
|
|
|
|
|
Alpha = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 32: /* 8 bits each of blue, green, red, and alpha */
|
|
|
|
|
case 24: /* 8 bits each of blue, green, and red. */
|
|
|
|
|
Blu = getbyte( ifp );
|
|
|
|
|
Grn = getbyte( ifp );
|
|
|
|
|
Red = getbyte( ifp );
|
|
|
|
|
if ( Size == 32 )
|
|
|
|
|
Alpha = getbyte( ifp );
|
|
|
|
|
else
|
|
|
|
|
Alpha = 0;
|
|
|
|
|
l = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
pm_error( "unknown pixel size (#2) - %d", Size );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PixEncode:
|
|
|
|
|
if ( mapped ) {
|
|
|
|
|
*dest = ColorMap[l];
|
|
|
|
|
if (has_alpha()) {
|
|
|
|
|
*alpha_p = AlphaMap[l];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
PPM_ASSIGN( *dest, Red, Grn, Blu );
|
|
|
|
|
if (has_alpha()) {
|
|
|
|
|
*alpha_p = Alpha;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned char PNMFileTypeTGA::Reader::
|
|
|
|
|
getbyte( FILE *ifp ) {
|
|
|
|
|
unsigned char c;
|
|
|
|
|
|
|
|
|
|
if ( fread( (char*) &c, 1, 1, ifp ) != 1 )
|
|
|
|
|
pm_error( "EOF / read error" );
|
|
|
|
|
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Writer::
|
|
|
|
|
writetga( struct ImageHeader *tgaP, char *id )
|
|
|
|
|
{
|
|
|
|
|
unsigned char flags;
|
|
|
|
|
|
|
|
|
|
fputc( tgaP->IDLength, _file );
|
|
|
|
|
fputc( tgaP->CoMapType, _file );
|
|
|
|
|
fputc( tgaP->ImgType, _file );
|
|
|
|
|
fputc( tgaP->Index_lo, _file );
|
|
|
|
|
fputc( tgaP->Index_hi, _file );
|
|
|
|
|
fputc( tgaP->Length_lo, _file );
|
|
|
|
|
fputc( tgaP->Length_hi, _file );
|
|
|
|
|
fputc( tgaP->CoSize, _file );
|
|
|
|
|
fputc( tgaP->X_org_lo, _file );
|
|
|
|
|
fputc( tgaP->X_org_hi, _file );
|
|
|
|
|
fputc( tgaP->Y_org_lo, _file );
|
|
|
|
|
fputc( tgaP->Y_org_hi, _file );
|
|
|
|
|
fputc( tgaP->Width_lo, _file );
|
|
|
|
|
fputc( tgaP->Width_hi, _file );
|
|
|
|
|
fputc( tgaP->Height_lo, _file );
|
|
|
|
|
fputc( tgaP->Height_hi, _file );
|
|
|
|
|
fputc( tgaP->PixelSize, _file );
|
|
|
|
|
flags = ( tgaP->AttBits & 0xf ) | ( ( tgaP->Rsrvd & 0x1 ) << 4 ) |
|
|
|
|
|
( ( tgaP->OrgBit & 0x1 ) << 5 ) | ( ( tgaP->OrgBit & 0x3 ) << 6 );
|
|
|
|
|
fputc( flags, _file );
|
|
|
|
|
if ( tgaP->IDLength )
|
|
|
|
|
fwrite( id, 1, (int) tgaP->IDLength, _file );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Writer::
|
|
|
|
|
put_map_entry( pixel* valueP, int size, pixval maxval )
|
|
|
|
|
{
|
|
|
|
|
int j;
|
|
|
|
|
pixel p;
|
|
|
|
|
|
|
|
|
|
switch ( size )
|
|
|
|
|
{
|
|
|
|
|
case 8: /* Grey scale. */
|
|
|
|
|
put_mono( valueP, maxval );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 16: /* 5 bits each of red green and blue. */
|
|
|
|
|
case 15: /* Watch for byte order. */
|
|
|
|
|
PPM_DEPTH( p, *valueP, maxval, 31 );
|
|
|
|
|
j = (int) PPM_GETB( p ) | ( (int) PPM_GETG( p ) << 5 ) |
|
|
|
|
|
( (int) PPM_GETR( p ) << 10 );
|
|
|
|
|
fputc( j % 256, _file );
|
|
|
|
|
fputc( j / 256, _file );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
|
case 24: /* 8 bits each of blue green and red. */
|
|
|
|
|
put_rgb( valueP, maxval );
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
pm_error( "unknown colormap pixel size (#2) - %d", size );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Writer::
|
|
|
|
|
compute_runlengths( int cols, pixel *pixelrow, int *runlength )
|
|
|
|
|
{
|
|
|
|
|
int col, start;
|
|
|
|
|
|
|
|
|
|
/* Initialize all run lengths to 0. (This is just an error check.) */
|
|
|
|
|
for ( col = 0; col < cols; ++col )
|
|
|
|
|
runlength[col] = 0;
|
|
|
|
|
|
|
|
|
|
/* Find runs of identical pixels. */
|
|
|
|
|
for ( col = 0; col < cols; )
|
|
|
|
|
{
|
|
|
|
|
start = col;
|
|
|
|
|
do {
|
|
|
|
|
++col;
|
|
|
|
|
}
|
|
|
|
|
while ( col < cols &&
|
|
|
|
|
col - start < 128 &&
|
|
|
|
|
PPM_EQUAL( pixelrow[col], pixelrow[start] ) );
|
|
|
|
|
runlength[start] = col - start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now look for runs of length-1 runs, and turn them into negative runs. */
|
|
|
|
|
for ( col = 0; col < cols; )
|
|
|
|
|
{
|
|
|
|
|
if ( runlength[col] == 1 )
|
|
|
|
|
{
|
|
|
|
|
start = col;
|
|
|
|
|
while ( col < cols &&
|
|
|
|
|
col - start < 128 &&
|
|
|
|
|
runlength[col] == 1 )
|
|
|
|
|
{
|
|
|
|
|
runlength[col] = 0;
|
|
|
|
|
++col;
|
|
|
|
|
}
|
|
|
|
|
runlength[start] = - ( col - start );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
col += runlength[col];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Writer::
|
|
|
|
|
put_pixel( pixel* pP, int imgtype, pixval maxval, colorhash_table cht )
|
|
|
|
|
{
|
|
|
|
|
switch ( imgtype )
|
|
|
|
|
{
|
|
|
|
|
case TGA_Mono:
|
|
|
|
|
case TGA_RLEMono:
|
|
|
|
|
put_mono( pP, maxval );
|
|
|
|
|
break;
|
|
|
|
|
case TGA_Map:
|
|
|
|
|
case TGA_RLEMap:
|
|
|
|
|
put_map( pP, cht );
|
|
|
|
|
break;
|
|
|
|
|
case TGA_RGB:
|
|
|
|
|
case TGA_RLERGB:
|
|
|
|
|
put_rgb( pP, maxval );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
pm_error( "can't happen" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Writer::
|
|
|
|
|
put_mono( pixel* pP, pixval maxval )
|
|
|
|
|
{
|
|
|
|
|
pixel p;
|
|
|
|
|
PPM_DEPTH( p, *pP, maxval, (pixval) 255 );
|
|
|
|
|
fputc( PPM_GETB( p ), _file );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Writer::
|
|
|
|
|
put_map( pixel *pP, colorhash_table cht )
|
|
|
|
|
{
|
|
|
|
|
fputc( ppm_lookupcolor( cht, pP ), _file );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PNMFileTypeTGA::Writer::
|
|
|
|
|
put_rgb( pixel* pP, pixval maxval ) {
|
|
|
|
|
pixel p;
|
|
|
|
|
PPM_DEPTH( p, *pP, maxval, (pixval) 255 );
|
|
|
|
|
fputc( PPM_GETB( p ), _file );
|
|
|
|
|
if (is_grayscale()) {
|
|
|
|
|
fputc( PPM_GETB( p ), _file );
|
|
|
|
|
fputc( PPM_GETB( p ), _file );
|
|
|
|
|
} else {
|
|
|
|
|
fputc( PPM_GETG( p ), _file );
|
|
|
|
|
fputc( PPM_GETR( p ), _file );
|
|
|
|
|
}
|
|
|
|
|
}
|