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