diff --git a/panda/src/pnmimagetypes/pnmFileTypeBMPWriter.cxx b/panda/src/pnmimagetypes/pnmFileTypeBMPWriter.cxx index 2d48840330..25297ce8fb 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeBMPWriter.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypeBMPWriter.cxx @@ -268,7 +268,8 @@ BMPwriterow( unsigned long cx, unsigned short bpp, int indexed, - colorhash_table cht) + colorhash_table cht, + xelval maxval) { BITSTREAM b; unsigned nbyte = 0; @@ -299,9 +300,9 @@ BMPwriterow( for (x = 0; x < cx; x++, row++) { - PutByte(fp, PPM_GETB(*row)); - PutByte(fp, PPM_GETG(*row)); - PutByte(fp, PPM_GETR(*row)); + PutByte(fp, PPM_GETB(*row) * 255 / maxval); + PutByte(fp, PPM_GETG(*row) * 255 / maxval); + PutByte(fp, PPM_GETR(*row) * 255 / maxval); nbyte += 3; } } @@ -329,7 +330,8 @@ BMPwritebits( unsigned short cBitCount, pixel **pixels, int indexed, - colorhash_table cht) + colorhash_table cht, + xelval maxval) { int nbyte = 0; long y; @@ -347,7 +349,8 @@ BMPwritebits( for (y = (long)cy - 1; y >= 0; y--) { int rc; - rc = BMPwriterow(fp, pixels[y], cx, cBitCount, indexed, cht); + rc = BMPwriterow(fp, pixels[y], cx, cBitCount, indexed, cht, + maxval); if(rc == -1) { @@ -460,7 +463,7 @@ BMPEncode( pm_error(er_internal, "BMPEncode"); } - nbyte += BMPwritebits(fp, x, y, bpp, pixels, true, cht); + nbyte += BMPwritebits(fp, x, y, bpp, pixels, true, cht, 255); if(nbyte != BMPlenfile(classv, bpp, x, y)) { pm_error(er_internal, "BMPEncode"); @@ -476,7 +479,8 @@ BMPEncode24( int classv, int x, int y, - pixel **pixels) + pixel **pixels, + xelval maxval) { unsigned long nbyte = 0; int bpp = 24; @@ -493,7 +497,8 @@ BMPEncode24( pm_error(er_internal, "BMPEncode24"); } - nbyte += BMPwritebits(fp, x, y, bpp, pixels, false, colorhash_table()); + nbyte += BMPwritebits(fp, x, y, bpp, pixels, false, colorhash_table(), + maxval); if(nbyte != BMPlenfile(classv, bpp, x, y)) { pm_error(er_internal, "BMPEncode24"); @@ -582,7 +587,7 @@ write_data(xel *array, xelval *) { chv = ppm_computecolorhist(pixels, _x_size, _y_size, MAXCOLORS, &colors); if (bmp_bpp > 8) { // Quietly generate a 24-bit image. - BMPEncode24(_file, classv, _x_size, _y_size, pixels); + BMPEncode24(_file, classv, _x_size, _y_size, pixels, _maxval); } else if (chv == (colorhist_vector) 0) { if (bmp_bpp != 0) { @@ -591,7 +596,7 @@ write_data(xel *array, xelval *) { << "too many colors for " << bmp_bpp << "-bit image.\n"; } - BMPEncode24(_file, classv, _x_size, _y_size, pixels); + BMPEncode24(_file, classv, _x_size, _y_size, pixels, _maxval); } else { pnmimage_bmp_cat.debug() diff --git a/panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx b/panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx index 43c6d87272..26f467c2a6 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx @@ -582,17 +582,6 @@ supports_read_row() const { return true; } -#define NEXTSAMPLE \ - { \ - if ( bitsleft == 0 ) \ - { \ - ++inP; \ - bitsleft = 8; \ - } \ - bitsleft -= bps; \ - sample = ( *inP >> bitsleft ) & _maxval; \ - } - //////////////////////////////////////////////////////////////////// // Function: PNMFileTypeTIFF::Reader::read_row // Access: Public, Virtual @@ -608,7 +597,9 @@ read_row(xel *row_data, xelval *alpha_data) { return false; } - unsigned char *buf = (unsigned char*) alloca((size_t)TIFFScanlineSize(tif)); + size_t scanline_size = (size_t)TIFFScanlineSize(tif); + unsigned char *buf = (unsigned char*) alloca(scanline_size); + int col; xelval gray, sample; xelval r, g, b; @@ -619,19 +610,42 @@ read_row(xel *row_data, xelval *alpha_data) { return false; } - unsigned char *inP = buf; + unsigned char *buf_ptr = buf; unsigned s; - int bitsleft = 8; + int bits_left = 8; + + // Get a pointer to a function that extracts the next bps-bit sample + // from the bitarray. There are a handful of different functions, + // which are optimized for different values of bps. + xelval (PNMFileTypeTIFF::Reader::*next_sample)(unsigned char *&buf_ptr, int &bits_left) const; + + if (bps < 8) { + next_sample = &PNMFileTypeTIFF::Reader::next_sample_lt_8; + + } else if (bps == 8) { + next_sample = &PNMFileTypeTIFF::Reader::next_sample_8; + + } else if (bps == 16) { + next_sample = &PNMFileTypeTIFF::Reader::next_sample_16; + + } else if (bps == 32) { + // Actually, it's not likely that a 32-bit sample will fit within + // a xelval. Deal with this when we come to it. + next_sample = &PNMFileTypeTIFF::Reader::next_sample_32; + + } else { + next_sample = &PNMFileTypeTIFF::Reader::next_sample_general; + } switch ( photomet ) { case PHOTOMETRIC_MINISBLACK: for ( col = 0; col < _x_size; ++col ) { - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); gray = sample; for (s = 1; s < spp; s++) { - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); if (s == unassoc_alpha_sample) { alpha_data[col] = sample; @@ -649,10 +663,10 @@ read_row(xel *row_data, xelval *alpha_data) { case PHOTOMETRIC_MINISWHITE: for ( col = 0; col < _x_size; ++col ) { - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); gray = _maxval - sample; for (s = 1; s < spp; s++) { - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); sample = _maxval - sample; if (s == unassoc_alpha_sample) { @@ -673,11 +687,11 @@ read_row(xel *row_data, xelval *alpha_data) { case PHOTOMETRIC_PALETTE: for ( col = 0; col < _x_size; ++col ) { - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); row_data[col] = colormap[sample]; for (s = 1; s < spp; s++) { - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); if (s == unassoc_alpha_sample) { alpha_data[col] = sample; @@ -699,15 +713,15 @@ read_row(xel *row_data, xelval *alpha_data) { case PHOTOMETRIC_RGB: for ( col = 0; col < _x_size; ++col ) { - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); r = sample; - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); g = sample; - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); b = sample; for (s = 3; s < spp; s++) { - NEXTSAMPLE; + sample = (this->*next_sample)(buf_ptr, bits_left); if (s == unassoc_alpha_sample) { alpha_data[col] = sample; @@ -731,10 +745,106 @@ read_row(xel *row_data, xelval *alpha_data) { return false; } + nassertr(buf_ptr <= buf + scanline_size, false); + current_row++; return true; } +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTIFF::Reader::next_sample_lt_8 +// Access: Private +// Description: Returns the next color sample from the row, when it +// is known that bps < 8. +//////////////////////////////////////////////////////////////////// +xelval PNMFileTypeTIFF::Reader:: +next_sample_lt_8(unsigned char *&buf_ptr, int &bits_left) const { + if (bits_left == 0) { + ++buf_ptr; + bits_left = 8; + } + + bits_left -= bps; + return (*buf_ptr >> bits_left) & _maxval; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTIFF::Reader::next_sample_8 +// Access: Private +// Description: Returns the next color sample from the row, when it +// is known that bps == 8. +//////////////////////////////////////////////////////////////////// +xelval PNMFileTypeTIFF::Reader:: +next_sample_8(unsigned char *&buf_ptr, int &bits_left) const { + return *buf_ptr++; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTIFF::Reader::next_sample_16 +// Access: Private +// Description: Returns the next color sample from the row, when it +// is known that bps == 16. +//////////////////////////////////////////////////////////////////// +xelval PNMFileTypeTIFF::Reader:: +next_sample_16(unsigned char *&buf_ptr, int &bits_left) const { + // The TIFF library has already byte-swapped the values if + // necessary. Thus, we only need to treat it as an array of shorts. + unsigned short result = *(unsigned short *)buf_ptr; + buf_ptr += 2; + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTIFF::Reader::next_sample_32 +// Access: Private +// Description: Returns the next color sample from the row, when it +// is known that bps == 32. +//////////////////////////////////////////////////////////////////// +xelval PNMFileTypeTIFF::Reader:: +next_sample_32(unsigned char *&buf_ptr, int &bits_left) const { + // The TIFF library has already byte-swapped the values if + // necessary. Thus, we only need to treat it as an array of longs. + unsigned long result = *(unsigned long *)buf_ptr; + buf_ptr += 2; + return (xelval)result; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeTIFF::Reader::next_sample_general +// Access: Private +// Description: Returns the next color sample from the row, in +// general. This unpacks an arbitrary string of bits +// from the sequence. +//////////////////////////////////////////////////////////////////// +xelval PNMFileTypeTIFF::Reader:: +next_sample_general(unsigned char *&buf_ptr, int &bits_left) const { + unsigned int result = 0; + int bits_needed = bps; + + while (bits_needed > 0) { + nassertr(bits_left >= 0, 0); + if (bits_left == 0) { + ++buf_ptr; + bits_left = 8; + } + + if (bits_needed <= bits_left) { + bits_left -= bits_needed; + unsigned int mask = (1 << bits_needed) - 1; + result |= ((*buf_ptr) >> bits_left) & mask; + bits_needed = 0; + + } else { + bits_needed -= bits_left; + unsigned int mask = (1 << bits_left) - 1; + result |= ((*buf_ptr) & mask) << bits_needed; + bits_left = 0; + } + } + + return result; +} + //////////////////////////////////////////////////////////////////// // Function: PNMFileTypeTIFF::Writer::Constructor diff --git a/panda/src/pnmimagetypes/pnmFileTypeTIFF.h b/panda/src/pnmimagetypes/pnmFileTypeTIFF.h index 1ffdcb0e46..d86631c82b 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeTIFF.h +++ b/panda/src/pnmimagetypes/pnmFileTypeTIFF.h @@ -63,6 +63,12 @@ public: virtual bool read_row(xel *array, xelval *alpha); private: + xelval next_sample_lt_8(unsigned char *&buf_ptr, int &bits_left) const; + xelval next_sample_8(unsigned char *&buf_ptr, int &bits_left) const; + xelval next_sample_16(unsigned char *&buf_ptr, int &bits_left) const; + xelval next_sample_32(unsigned char *&buf_ptr, int &bits_left) const; + xelval next_sample_general(unsigned char *&buf_ptr, int &bits_left) const; + unsigned short photomet; unsigned short bps, spp; unsigned short unassoc_alpha_sample, assoc_alpha_sample;