15 #include "pnmFileTypeSGI.h" 19 #include "config_pnmimagetypes.h" 23 #include "pnmReader.h" 48 typedef PNMFileTypeSGI::Reader::TabEntry TabEntry;
50 typedef short ScanElem;
51 typedef ScanElem * ScanLine;
54 static unsigned char get_byte ( istream* f );
55 static long get_big_long (istream *f);
56 static short get_big_short (istream *f);
57 static short get_byte_as_short (istream *f);
58 static int readerr (istream *f);
59 static void * xmalloc (
int bytes);
60 #define MALLOC(n, type) (type *)xmalloc((n) * sizeof(type)) 61 static const char * compression_name (
char compr);
62 static void read_bytes (istream *ifp,
int n,
char *buf);
63 static bool read_header(istream *ifp,
Header *head,
const string &magic_number);
64 static TabEntry * read_table (istream *ifp,
int tablen);
65 static void read_channel (istream *ifp,
int xsize,
int ysize,
66 int zsize,
int bpc, TabEntry *table,
67 ScanElem *channel_data,
long table_start,
68 int channel,
int row);
69 static void rle_decompress (ScanElem *src,
long srclen, ScanElem *dest,
long destlen);
71 #define WORSTCOMPR(x) (2*(x) + 2) 73 #define MAXVAL_BYTE 255 74 #define MAXVAL_WORD 65535 79 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 = 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";
152 PNMFileTypeSGI::Reader::
169 bool PNMFileTypeSGI::Reader::
170 supports_read_row()
const {
183 bool PNMFileTypeSGI::Reader::
184 read_row(
xel *row_data, xelval *alpha_data,
int x_size,
int y_size) {
188 nassertr(current_row >= 0,
false);
190 ScanElem *red = (ScanElem *)alloca(x_size *
sizeof(ScanElem));
191 ScanElem *grn = (ScanElem *)alloca(x_size *
sizeof(ScanElem));
192 ScanElem *blu = (ScanElem *)alloca(x_size *
sizeof(ScanElem));
193 ScanElem *alpha = (ScanElem *)alloca(x_size *
sizeof(ScanElem));
195 read_channel(_file, x_size, y_size, _num_channels, bpc, table, red,
196 table_start, 0, current_row);
199 read_channel(_file, x_size, y_size, _num_channels, bpc, table, grn,
200 table_start, 1, current_row);
201 read_channel(_file, x_size, y_size, _num_channels, bpc, table, blu,
202 table_start, 2, current_row);
206 read_channel(_file, x_size, y_size, _num_channels, bpc, table, alpha,
207 table_start, _num_channels - 1, current_row);
210 for (
int x = 0; x < x_size; x++) {
212 PPM_PUTB(row_data[x], (xelval)red[x]);
218 PPM_ASSIGN(row_data[x], r, g, b);
222 alpha_data[x] = (xelval)alpha[x];
233 nassertr(magic_number.size() == 4,
false);
235 ((
unsigned char)magic_number[0] << 8) |
236 ((
unsigned char)magic_number[1]);
237 head->storage = (
unsigned char)magic_number[2];
238 head->bpc = (
unsigned char)magic_number[3];
239 head->dimension = get_big_short(ifp);
240 head->xsize = get_big_short(ifp);
241 head->ysize = get_big_short(ifp);
242 head->zsize = get_big_short(ifp);
243 head->pixmin = get_big_long(ifp);
244 head->pixmax = get_big_long(ifp);
245 read_bytes(ifp, 4, head->dummy1);
246 read_bytes(ifp, 80, head->name);
247 head->colormap = get_big_long(ifp);
248 read_bytes(ifp, 404, head->dummy2);
250 if (head->magic != SGI_MAGIC) {
251 pnmimage_sgi_cat.error()
252 <<
"Invalid magic number: not an SGI image file.\n";
256 if (head->storage != 0 && head->storage != 1) {
257 pnmimage_sgi_cat.error()
258 <<
"Unknown compression type.\n";
262 if (head->bpc < 1 || head->bpc > 2) {
263 pnmimage_sgi_cat.error()
264 <<
"Illegal precision value " << head->bpc <<
" (only 1-2 allowed)\n";
324 read_table(istream *ifp,
int tablen) {
328 table = MALLOC(tablen, TabEntry);
330 for( i = 0; i < tablen; i++ ) {
331 table[i].start = get_big_long(ifp);
333 for( i = 0; i < tablen; i++ ) {
334 table[i].length = get_big_long(ifp);
343 read_channel(istream *ifp,
344 int xsize,
int ysize,
int,
int bpc,
346 ScanElem *channel_data,
long table_start,
347 int channel,
int row) {
348 ScanElem *temp = NULL;
352 short (*func)(istream *);
353 func = (bpc==1) ? get_byte_as_short : get_big_short;
356 temp = (ScanElem *)alloca(WORSTCOMPR(xsize) *
sizeof(ScanElem));
359 sgi_index = channel * ysize + row;
361 offset = table[sgi_index].start;
362 length = table[sgi_index].length;
365 if(!ifp->seekg(offset))
366 pm_error(
"seek error for offset %ld", offset);
368 nassertv(length <= WORSTCOMPR(xsize));
369 for( i = 0; i < length; i++ )
370 temp[i] = (*func)(ifp);
372 rle_decompress(temp, length, channel_data, xsize);
375 offset = sgi_index * xsize + table_start;
376 if(!ifp->seekg(offset))
377 pm_error(
"seek error for offset %ld", offset);
378 for( i = 0; i < xsize; i++ )
379 channel_data[i] = (*func)(ifp);
386 rle_decompress(ScanElem *src,
394 el = (
unsigned char)(*src++ & 0xff);
396 count = (int)(el & 0x7f);
400 if( destleft < count )
401 pm_error(
"RLE error: too much input data (space left %d, need %d)", destleft, count);
404 if( srcleft < count )
405 pm_error(
"RLE error: not enough data for literal run (data left %d, need %d)", srcleft, count);
412 pm_error(
"RLE error: not enough data for replicate run");
419 pm_error(
"RLE error: no terminating 0-byte");
426 get_big_short(istream *ifp) {
429 if( pm_readbigshort(ifp, &s) == -1 )
436 get_big_long(istream *ifp) {
439 if( pm_readbiglong(ifp, &l) == -1 )
446 get_byte(istream *ifp) {
453 return (
unsigned char) i;
458 readerr(istream *f) {
461 pnmimage_sgi_cat.warning()
462 <<
"Read error on file.\n";
464 pnmimage_sgi_cat.warning()
465 <<
"Premature EOF on file.\n";
475 read_bytes(istream *ifp,
484 memset(buf+r, 0, n-r);
491 get_byte_as_short(istream *ifp) {
492 return (
short)get_byte(ifp);
505 pm_error(
"out of memory allocating %d bytes", bytes);
510 compression_name(
char compr) {
512 case STORAGE_VERBATIM:
521 #endif // HAVE_SGI_RGB bool is_valid() const
Returns true if the PNMWriter can be used to write data, false if something is wrong.
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...
This is an abstract base class that defines the interface for reading image files of various types...