50 typedef PNMFileTypeSGI::Reader::TabEntry TabEntry;
52 typedef short ScanElem;
53 typedef ScanElem * ScanLine;
56 static unsigned char get_byte ( istream* f );
57 static long get_big_long (istream *f);
58 static short get_big_short (istream *f);
59 static short get_byte_as_short (istream *f);
60 static int readerr (istream *f);
61 static void * xmalloc (
int bytes);
62 #define MALLOC(n, type) (type *)xmalloc((n) * sizeof(type)) 63 static const char * compression_name (
char compr);
64 static void read_bytes (istream *ifp,
int n,
char *buf);
65 static bool read_header(istream *ifp,
Header *head,
const string &magic_number);
66 static TabEntry * read_table (istream *ifp,
int tablen);
67 static void read_channel (istream *ifp,
int xsize,
int ysize,
68 int zsize,
int bpc, TabEntry *table,
69 ScanElem *channel_data,
long table_start,
70 int channel,
int row);
71 static void rle_decompress (ScanElem *src,
long srclen, ScanElem *dest,
long destlen);
73 #define WORSTCOMPR(x) (2*(x) + 2) 75 #define MAXVAL_BYTE 255 76 #define MAXVAL_WORD 65535 81 static bool eof_err =
false;
87 PNMFileTypeSGI::Reader::
88 Reader(
PNMFileType *type, istream *file,
bool owns_file,
string magic_number) :
96 if (pnmimage_sgi_cat.is_debug()) {
97 pnmimage_sgi_cat.debug()
98 <<
"RGB file appears to be empty.\n";
110 long pixmax = (head.bpc == 1) ? MAXVAL_BYTE : MAXVAL_WORD;
111 if( pixmax > PNM_MAXMAXVAL ) {
112 pnmimage_sgi_cat.error()
113 <<
"Cannot read RGB image with maxval of " << pixmax
114 <<
"--largest allowable maxval is currently " << PNM_MAXMAXVAL <<
"\n";
119 _maxval = (xelval)pixmax;
121 table_start = file->tellg();
122 if( head.storage != STORAGE_VERBATIM )
123 table = read_table(file, head.ysize * head.zsize);
125 _x_size = head.xsize;
126 _y_size = head.ysize;
127 _num_channels = std::min((
int)head.zsize, 4);
130 current_row = _y_size - 1;
132 if (_is_valid && pnmimage_sgi_cat.is_debug()) {
133 head.name[79] =
'\0';
134 pnmimage_sgi_cat.debug()
135 <<
"Read RGB image:\n" 136 <<
" raster size " << head.xsize <<
" x " << head.ysize
137 <<
", " << head.zsize <<
" channels\n" 138 <<
" compression: " << (int)head.storage <<
" = " 139 << compression_name(head.storage) <<
"\n" 140 <<
" image name: " << head.name <<
"\n" 141 <<
" bpc: " << (int)head.bpc <<
" dimension: " << head.dimension <<
"\n" 142 <<
" pixmin: " << head.pixmin <<
" pixmax: " << head.pixmax
143 <<
" colormap: " << head.colormap <<
"\n";
150 PNMFileTypeSGI::Reader::
152 if (table !=
nullptr) {
163 bool PNMFileTypeSGI::Reader::
164 supports_read_row()
const {
174 bool PNMFileTypeSGI::Reader::
175 read_row(
xel *row_data, xelval *alpha_data,
int x_size,
int y_size) {
179 nassertr(current_row >= 0,
false);
181 ScanElem *red = (ScanElem *)alloca(x_size *
sizeof(ScanElem));
182 ScanElem *grn = (ScanElem *)alloca(x_size *
sizeof(ScanElem));
183 ScanElem *blu = (ScanElem *)alloca(x_size *
sizeof(ScanElem));
184 ScanElem *alpha = (ScanElem *)alloca(x_size *
sizeof(ScanElem));
186 read_channel(_file, x_size, y_size, _num_channels, bpc, table, red,
187 table_start, 0, current_row);
189 if (!is_grayscale()) {
190 read_channel(_file, x_size, y_size, _num_channels, bpc, table, grn,
191 table_start, 1, current_row);
192 read_channel(_file, x_size, y_size, _num_channels, bpc, table, blu,
193 table_start, 2, current_row);
197 read_channel(_file, x_size, y_size, _num_channels, bpc, table, alpha,
198 table_start, _num_channels - 1, current_row);
201 for (
int x = 0; x < x_size; x++) {
202 if (is_grayscale()) {
203 PPM_PUTB(row_data[x], (xelval)red[x]);
209 PPM_ASSIGN(row_data[x], r, g, b);
213 alpha_data[x] = (xelval)alpha[x];
223 read_header(istream *ifp,
Header *head,
const string &magic_number) {
224 nassertr(magic_number.size() == 4,
false);
226 ((
unsigned char)magic_number[0] << 8) |
227 ((
unsigned char)magic_number[1]);
228 head->storage = (
unsigned char)magic_number[2];
229 head->bpc = (
unsigned char)magic_number[3];
230 head->dimension = get_big_short(ifp);
231 head->xsize = get_big_short(ifp);
232 head->ysize = get_big_short(ifp);
233 head->zsize = get_big_short(ifp);
234 head->pixmin = get_big_long(ifp);
235 head->pixmax = get_big_long(ifp);
236 read_bytes(ifp, 4, head->dummy1);
237 read_bytes(ifp, 80, head->name);
238 head->colormap = get_big_long(ifp);
239 read_bytes(ifp, 404, head->dummy2);
241 if (head->magic != SGI_MAGIC) {
242 pnmimage_sgi_cat.error()
243 <<
"Invalid magic number: not an SGI image file.\n";
247 if (head->storage != 0 && head->storage != 1) {
248 pnmimage_sgi_cat.error()
249 <<
"Unknown compression type.\n";
253 if (head->bpc < 1 || head->bpc > 2) {
254 pnmimage_sgi_cat.error()
255 <<
"Illegal precision value " << head->bpc <<
" (only 1-2 allowed)\n";
315 read_table(istream *ifp,
int tablen) {
319 table = MALLOC(tablen, TabEntry);
321 for( i = 0; i < tablen; i++ ) {
322 table[i].start = get_big_long(ifp);
324 for( i = 0; i < tablen; i++ ) {
325 table[i].length = get_big_long(ifp);
334 read_channel(istream *ifp,
335 int xsize,
int ysize,
int,
int bpc,
337 ScanElem *channel_data,
long table_start,
338 int channel,
int row) {
339 ScanElem *temp =
nullptr;
343 short (*func)(istream *);
344 func = (bpc==1) ? get_byte_as_short : get_big_short;
347 temp = (ScanElem *)alloca(WORSTCOMPR(xsize) *
sizeof(ScanElem));
350 sgi_index = channel * ysize + row;
352 offset = table[sgi_index].start;
353 length = table[sgi_index].length;
356 if(!ifp->seekg(offset))
357 pm_error(
"seek error for offset %ld", offset);
359 nassertv(length <= WORSTCOMPR(xsize));
360 for( i = 0; i < length; i++ )
361 temp[i] = (*func)(ifp);
363 rle_decompress(temp, length, channel_data, xsize);
366 offset = sgi_index * xsize + table_start;
367 if(!ifp->seekg(offset))
368 pm_error(
"seek error for offset %ld", offset);
369 for( i = 0; i < xsize; i++ )
370 channel_data[i] = (*func)(ifp);
377 rle_decompress(ScanElem *src,
385 el = (
unsigned char)(*src++ & 0xff);
387 count = (int)(el & 0x7f);
391 if( destleft < count )
392 pm_error(
"RLE error: too much input data (space left %d, need %d)", destleft, count);
395 if( srcleft < count )
396 pm_error(
"RLE error: not enough data for literal run (data left %d, need %d)", srcleft, count);
403 pm_error(
"RLE error: not enough data for replicate run");
410 pm_error(
"RLE error: no terminating 0-byte");
417 get_big_short(istream *ifp) {
420 if( pm_readbigshort(ifp, &s) == -1 )
427 get_big_long(istream *ifp) {
430 if( pm_readbiglong(ifp, &l) == -1 )
437 get_byte(istream *ifp) {
444 return (
unsigned char) i;
449 readerr(istream *f) {
452 pnmimage_sgi_cat.warning()
453 <<
"Read error on file.\n";
455 pnmimage_sgi_cat.warning()
456 <<
"Premature EOF on file.\n";
466 read_bytes(istream *ifp,
475 memset(buf+r, 0, n-r);
482 get_byte_as_short(istream *ifp) {
483 return (
short)get_byte(ifp);
496 pm_error(
"out of memory allocating %d bytes", bytes);
501 compression_name(
char compr) {
503 case STORAGE_VERBATIM:
512 #endif // HAVE_SGI_RGB
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the base class of a family of classes that represent particular image file types that PNMImag...
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
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.
This is an abstract base class that defines the interface for reading image files of various types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.