diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 2985499c53..b93293b218 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -1979,6 +1979,7 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath, x_size = 1; y_size = 1; } + image = PNMImage(x_size, y_size, image.get_num_channels(), image.get_maxval(), image.get_type()); image.fill(0.2, 0.3, 1.0); @@ -1987,6 +1988,19 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath, } } else { + if (!image.read_header(fullpath, NULL, false)) { + gobj_cat.error() + << "Texture::read() - couldn't read: " << fullpath << endl; + return false; + } + + if (z == 0 && n == 0) { + consider_rescale(image, fullpath.get_basename()); + } else { + image.set_read_size(get_expected_mipmap_x_size(n), + get_expected_mipmap_y_size(n)); + } + if (!image.read(fullpath, NULL, false)) { gobj_cat.error() << "Texture::read() - couldn't read: " << fullpath << endl; @@ -2021,6 +2035,22 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath, } } else { + if (!alpha_image.read_header(alpha_fullpath, NULL, true)) { + gobj_cat.error() + << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl; + return false; + } + + if (image.get_x_size() != alpha_image.get_x_size() || + image.get_y_size() != alpha_image.get_y_size()) { + gobj_cat.info() + << "Implicitly rescaling " << alpha_fullpath.get_basename() + << " from " << alpha_image.get_x_size() << " by " + << alpha_image.get_y_size() << " to " << image.get_x_size() + << " by " << image.get_y_size() << "\n"; + alpha_image.set_read_size(image.get_x_size(), image.get_y_size()); + } + if (!alpha_image.read(alpha_fullpath, NULL, true)) { gobj_cat.error() << "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl; @@ -2045,13 +2075,12 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath, set_fullpath(fullpath); set_alpha_fullpath(alpha_fullpath); - - consider_rescale(image, fullpath.get_basename()); } if (!alpha_fullpath.empty()) { - // The grayscale (alpha channel) image must be the same size as the - // main image. + // The grayscale (alpha channel) image must be the same size as + // the main image. This should really have been already + // guaranteed by the above. if (image.get_x_size() != alpha_image.get_x_size() || image.get_y_size() != alpha_image.get_y_size()) { gobj_cat.info() @@ -2818,8 +2847,13 @@ clear_prepared(PreparedGraphicsObjects *prepared_objects) { //////////////////////////////////////////////////////////////////// // Function: Texture::consider_rescale // Access: Private -// Description: Scales the PNMImage according to the whims of the -// Config.prc file. +// Description: Asks the PNMImage to change its scale when it reads +// the image, according to the whims of the Config.prc +// file. +// +// This method should be called after +// pnmimage.read_header() has been called, but before +// pnmimage.read(). //////////////////////////////////////////////////////////////////// void Texture:: consider_rescale(PNMImage &pnmimage, const string &name) { @@ -2877,14 +2911,11 @@ consider_rescale(PNMImage &pnmimage, const string &name) { if (pnmimage.get_x_size() != new_x_size || pnmimage.get_y_size() != new_y_size) { gobj_cat.info() - << "Automatically rescaling " << name << " from " + << "Implicitly rescaling " << name << " from " << pnmimage.get_x_size() << " by " << pnmimage.get_y_size() << " to " << new_x_size << " by " << new_y_size << "\n"; - PNMImage scaled(new_x_size, new_y_size, pnmimage.get_num_channels(), - pnmimage.get_maxval(), pnmimage.get_type()); - scaled.quick_filter_from(pnmimage); - pnmimage = scaled; + pnmimage.set_read_size(new_x_size, new_y_size); } } diff --git a/panda/src/pnmimage/pnmImage.I b/panda/src/pnmimage/pnmImage.I index 3c287944ab..552e2607b9 100644 --- a/panda/src/pnmimage/pnmImage.I +++ b/panda/src/pnmimage/pnmImage.I @@ -25,6 +25,8 @@ INLINE PNMImage:: PNMImage() { _array = NULL; _alpha = NULL; + + clear(); } //////////////////////////////////////////////////////////////////// @@ -155,6 +157,39 @@ alpha_fill(double alpha) { alpha_fill_val((xelval)(alpha * get_maxval())); } +//////////////////////////////////////////////////////////////////// +// Function: PNMImage::set_read_size +// Access: Published +// Description: Specifies the size to we'd like to scale the image +// upon reading it. This will affect the next call to +// read(). This is usually used to reduce the image +// size, e.g. for a thumbnail. +// +// If the file type reader supports it (e.g. JPEG), then +// this will scale the image during the read operation, +// consequently reducing memory and CPU utilization. If +// the file type reader does not support it, this will +// load the image normally, and them perform a linear +// scale after it has been loaded. +//////////////////////////////////////////////////////////////////// +INLINE void PNMImage:: +set_read_size(int x_size, int y_size) { + _read_x_size = x_size; + _read_y_size = y_size; + _has_read_size = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMImage::clear_read_size +// Access: Published +// Description: Undoes the effect of a previous call to +// set_read_size(). +//////////////////////////////////////////////////////////////////// +INLINE void PNMImage:: +clear_read_size() { + _has_read_size = false; +} + //////////////////////////////////////////////////////////////////// // Function: PNMImage::is_valid // Access: Published diff --git a/panda/src/pnmimage/pnmImage.cxx b/panda/src/pnmimage/pnmImage.cxx index da7b0f5f62..90379b8b87 100644 --- a/panda/src/pnmimage/pnmImage.cxx +++ b/panda/src/pnmimage/pnmImage.cxx @@ -31,6 +31,7 @@ PNMImage:: PNMImage(const Filename &filename, PNMFileType *type) { _array = NULL; _alpha = NULL; + _has_read_size = false; bool result = read(filename, type); if (!result) { @@ -61,6 +62,7 @@ clear() { _maxval = 255; _comment.clear(); _type = (PNMFileType *)NULL; + _has_read_size = false; } //////////////////////////////////////////////////////////////////// @@ -81,6 +83,7 @@ clear(int x_size, int y_size, int num_channels, _maxval = maxval; _comment.clear(); _type = type; + _has_read_size = false; if (has_alpha()) { allocate_alpha(); @@ -220,13 +223,12 @@ remix_channels(const LMatrix4f &conv) { //////////////////////////////////////////////////////////////////// bool PNMImage:: read(const Filename &filename, PNMFileType *type, bool report_unknown_type) { - clear(); - - PNMReader *reader = PNMImageHeader::make_reader(filename, type, - report_unknown_type); + PNMReader *reader = make_reader(filename, type, report_unknown_type); if (reader == (PNMReader *)NULL) { + clear(); return false; } + return read(reader); } @@ -247,11 +249,10 @@ read(const Filename &filename, PNMFileType *type, bool report_unknown_type) { bool PNMImage:: read(istream &data, const string &filename, PNMFileType *type, bool report_unknown_type) { - clear(); - PNMReader *reader = PNMImageHeader::make_reader (&data, false, filename, string(), type, report_unknown_type); if (reader == (PNMReader *)NULL) { + clear(); return false; } return read(reader); @@ -272,6 +273,10 @@ read(istream &data, const string &filename, PNMFileType *type, //////////////////////////////////////////////////////////////////// bool PNMImage:: read(PNMReader *reader) { + bool has_read_size = _has_read_size; + int read_x_size = _read_x_size; + int read_y_size = _read_y_size; + clear(); if (reader == NULL) { @@ -283,6 +288,11 @@ read(PNMReader *reader) { return false; } + if (has_read_size) { + reader->set_read_size(read_x_size, read_y_size); + } + reader->prepare_read(); + copy_header_from(*reader); // We reassign y_size after reading because we might have read a @@ -293,10 +303,20 @@ read(PNMReader *reader) { if (_y_size == 0) { clear(); return false; - } else { - setup_rc(); - return true; } + + setup_rc(); + + if (has_read_size && (_x_size != read_x_size || _y_size != read_y_size)) { + // The Reader didn't comply with our size request. Do the sizing + // explicitly, then. + PNMImage new_image(read_x_size, read_y_size, get_num_channels(), + get_maxval(), get_type()); + new_image.quick_filter_from(*this); + take_from(new_image); + } + + return true; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pnmimage/pnmImage.h b/panda/src/pnmimage/pnmImage.h index f114615fd4..f5b1b7ca2d 100644 --- a/panda/src/pnmimage/pnmImage.h +++ b/panda/src/pnmimage/pnmImage.h @@ -91,6 +91,9 @@ PUBLISHED: INLINE void alpha_fill(double alpha = 0.0); void alpha_fill_val(xelval alpha = 0); + INLINE void set_read_size(int x_size, int y_size); + INLINE void clear_read_size(); + bool read(const Filename &filename, PNMFileType *type = NULL, bool report_unknown_type = true); bool read(istream &data, const string &filename = string(), @@ -239,6 +242,9 @@ private: xel *_array; xelval *_alpha; double _default_rc, _default_gc, _default_bc; + + int _read_x_size, _read_y_size; + bool _has_read_size; }; #include "pnmImage.I" diff --git a/panda/src/pnmimage/pnmImageHeader.cxx b/panda/src/pnmimage/pnmImageHeader.cxx index ece9b53533..eeb2d317d8 100644 --- a/panda/src/pnmimage/pnmImageHeader.cxx +++ b/panda/src/pnmimage/pnmImageHeader.cxx @@ -35,8 +35,9 @@ // false. //////////////////////////////////////////////////////////////////// bool PNMImageHeader:: -read_header(const Filename &filename, PNMFileType *type) { - PNMReader *reader = make_reader(filename, type); +read_header(const Filename &filename, PNMFileType *type, + bool report_unknown_type) { + PNMReader *reader = make_reader(filename, type, report_unknown_type); if (reader != (PNMReader *)NULL) { (*this) = (*reader); delete reader; diff --git a/panda/src/pnmimage/pnmImageHeader.h b/panda/src/pnmimage/pnmImageHeader.h index f31ab096a5..d418391773 100644 --- a/panda/src/pnmimage/pnmImageHeader.h +++ b/panda/src/pnmimage/pnmImageHeader.h @@ -82,7 +82,8 @@ PUBLISHED: INLINE PNMFileType *get_type() const; INLINE void set_type(PNMFileType *type); - bool read_header(const Filename &filename, PNMFileType *type = NULL); + bool read_header(const Filename &filename, PNMFileType *type = NULL, + bool report_unknown_type = true); PNMReader *make_reader(const Filename &filename, PNMFileType *type = NULL, diff --git a/panda/src/pnmimage/pnmReader.I b/panda/src/pnmimage/pnmReader.I index 341b2decb4..63c28c26a7 100644 --- a/panda/src/pnmimage/pnmReader.I +++ b/panda/src/pnmimage/pnmReader.I @@ -26,10 +26,28 @@ PNMReader(PNMFileType *type, istream *file, bool owns_file) : _type(type), _owns_file(owns_file), _file(file), - _is_valid(true) + _is_valid(true), + _has_read_size(false) { } +//////////////////////////////////////////////////////////////////// +// Function: PNMReader::set_read_size +// Access: Public +// Description: Instructs the reader to attempt to scale the image to +// the indicated size while reading it. The reader may +// or may not follow this suggestion, or may follow it +// only partially (e.g. by reading a file which is +// slightly reduced in size, but not the precise size +// requested). +//////////////////////////////////////////////////////////////////// +void PNMReader:: +set_read_size(int x_size, int y_size) { + _read_x_size = x_size; + _read_y_size = y_size; + _has_read_size = true; +} + //////////////////////////////////////////////////////////////////// // Function: PNMReader::get_type // Access: Public diff --git a/panda/src/pnmimage/pnmReader.cxx b/panda/src/pnmimage/pnmReader.cxx index a36660a977..e24671a2be 100644 --- a/panda/src/pnmimage/pnmReader.cxx +++ b/panda/src/pnmimage/pnmReader.cxx @@ -39,6 +39,40 @@ PNMReader:: _file = (istream *)NULL; } +//////////////////////////////////////////////////////////////////// +// Function: PNMReader::prepare_read +// Access: Public, Virtual +// Description: This method will be called before read_data() or +// read_row() is called. It instructs the reader to +// initialize its data structures as necessary to +// actually perform the read operation. +// +// After this call, _x_size and _y_size should reflect +// the actual size that will be filled by read_data() +// (as possibly modified by set_read_size()). +//////////////////////////////////////////////////////////////////// +void PNMReader:: +prepare_read() { + if (!_is_valid) { + return; + } + + _x_shift = 0; + _y_shift = 0; + _orig_x_size = _x_size; + _orig_y_size = _y_size; + + if (supports_read_row()) { + // Maybe we can quick-filter each row down as we go. + if (_has_read_size) { + _x_shift = get_reduction_shift(_x_size, _read_x_size); + _x_size = _x_size / (1 << _x_shift); + _y_shift = get_reduction_shift(_y_size, _read_y_size); + _y_size = _y_size / (1 << _y_shift); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: PNMReader::read_data // Access: Public, Virtual @@ -58,12 +92,102 @@ read_data(xel *array, xelval *alpha) { return 0; } - int y; - for (y = 0; y < _y_size; y++) { - if (!read_row(array + y * _x_size, alpha + y * _x_size)) { - return y; + if (_x_shift == 0 && _y_shift == 0) { + // Read with no reduction. + int y; + for (y = 0; y < _y_size; ++y) { + if (!read_row(array + y * _x_size, alpha + y * _x_size, _x_size, _y_size)) { + return y; + } + } + + } else { + int x_reduction = (1 << _x_shift); + int y_reduction = (1 << _y_shift); + + int shift = _x_shift + _y_shift; + + // We need a temporary buffer, at least one row wide, with + // full-width integers, for accumulating pixel data. + int *accum_row_array = (int *)alloca(_orig_x_size * sizeof(int) * 3); + int *accum_row_alpha = (int *)alloca(_orig_x_size * sizeof(int)); + + // Each time we read a row, we will actually read the full row + // here, before we filter it down into the above. + xel *orig_row_array = (xel *)alloca(_orig_x_size * sizeof(xel)); + xelval *orig_row_alpha = (xelval *)alloca(_orig_x_size * sizeof(xelval)); + + int y; + for (y = 0; y < _y_size; ++y) { + // Zero out the accumulation data, in preparation for + // holding the results of the below. + memset(accum_row_array, 0, _x_size * sizeof(int) * 3); + if (has_alpha()) { + memset(accum_row_alpha, 0, _x_size * sizeof(int)); + } + + for (int yi = 0; yi < y_reduction; ++yi) { + // OK, read a row. This reads the original, full-size row. + if (!read_row(orig_row_array, orig_row_alpha, _orig_x_size, _orig_y_size)) { + return y; + } + + // Boil that row down to its proper, reduced size, and + // accumulate it into the target row. + xel *p = orig_row_array; + int *q = accum_row_array; + int *qstop = q + _x_size * 3; + while (q < qstop) { + for (int xi = 0; xi < x_reduction; ++xi) { + q[0] += (*p).r; + q[1] += (*p).g; + q[2] += (*p).b; + ++p; + } + q += 3; + } + if (has_alpha()) { + // Now do it again for the alpha channel. + xelval *p = orig_row_alpha; + int *q = accum_row_alpha; + int *qstop = q + _x_size; + while (q < qstop) { + for (int xi = 0; xi < x_reduction; ++xi) { + (*q) += (*p); + ++p; + } + ++q; + } + } + } + + // OK, now copy the accumulated pixel data into the final + // result. + xel *target_row_array = array + y * _x_size; + xelval *target_row_alpha = alpha + y * _x_size; + + int *p = accum_row_array; + xel *q = target_row_array; + xel *qstop = q + _x_size; + while (q < qstop) { + (*q).r = (*p++) >> shift; + (*q).g = (*p++) >> shift; + (*q).b = (*p++) >> shift; + ++q; + } + + if (has_alpha()) { + int *p = accum_row_alpha; + xelval *q = target_row_alpha; + xelval *qstop = q + _x_size; + while (q < qstop) { + (*q) = (*p++) >> shift; + ++q; + } + } } } + return _y_size; } @@ -91,9 +215,17 @@ supports_read_row() const { // one horizontal row at a time, beginning from the top. // Returns true if the row is successfully read, false // if there is an error or end of file. +// +// The x_size and y_size parameters are the value of +// _x_size and _y_size as originally filled in by the +// constructor; it is the actual number of pixels in the +// image. (The _x_size and _y_size members may have +// been automatically modified by the time this method +// is called if we are scaling on load, so should not be +// used.) //////////////////////////////////////////////////////////////////// bool PNMReader:: -read_row(xel *, xelval *) { +read_row(xel *, xelval *, int, int) { return false; } @@ -111,3 +243,38 @@ bool PNMReader:: supports_stream_read() const { return false; } + +//////////////////////////////////////////////////////////////////// +// Function: PNMReader::get_reduction_shift +// Access: Private +// Description: Determines the reduction factor between the original +// size and the requested size, returned as an exponent +// of power of 2 (that is, a bit shift). +// +// Only power-of-two reductions are supported, since +// those are common, easy, and fast. Other reductions +// will be handled in the higher level code. +//////////////////////////////////////////////////////////////////// +int PNMReader:: +get_reduction_shift(int orig_size, int new_size) { + if (new_size == 0) { + return 0; + } + + int reduction = max(orig_size / new_size, 1); + + int shift = 0; + + int r = 2; + while (r <= reduction) { + shift += 1; + r <<= 1; + } + + if ((orig_size % r) != 0) { + // If the reduction isn't even, never mind. + shift = 0; + } + + return shift; +} diff --git a/panda/src/pnmimage/pnmReader.h b/panda/src/pnmimage/pnmReader.h index 878c22f146..c0fbb4d5f1 100644 --- a/panda/src/pnmimage/pnmReader.h +++ b/panda/src/pnmimage/pnmReader.h @@ -38,22 +38,33 @@ protected: public: virtual ~PNMReader(); + INLINE void set_read_size(int x_size, int y_size); INLINE PNMFileType *get_type() const; + virtual void prepare_read(); virtual int read_data(xel *array, xelval *alpha); virtual bool supports_read_row() const; - virtual bool read_row(xel *array, xelval *alpha); + virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size); virtual bool supports_stream_read() const; INLINE bool is_valid() const; +private: + int get_reduction_shift(int orig_size, int new_size); + protected: PNMFileType *_type; bool _owns_file; istream *_file; bool _is_valid; + + int _read_x_size, _read_y_size; + bool _has_read_size; + + int _x_shift, _y_shift; + int _orig_x_size, _orig_y_size; }; #include "pnmReader.I" diff --git a/panda/src/pnmimagetypes/config_pnmimagetypes.cxx b/panda/src/pnmimagetypes/config_pnmimagetypes.cxx index e4ddb4a6dc..63a7d7a931 100644 --- a/panda/src/pnmimagetypes/config_pnmimagetypes.cxx +++ b/panda/src/pnmimagetypes/config_pnmimagetypes.cxx @@ -90,18 +90,6 @@ ConfigVariableInt jpeg_quality "size).")); -// These control the scaling that is automatically performed on a JPEG -// file for decompression. You might specify to scale down by a -// fraction, e.g. 1/8, by specifying jpeg_scale_num = 1 and -// jpeg_scale_denom = 8. This will reduce decompression time -// correspondingly. Attempting to use this to scale up, or to scale -// by any fraction other than an even power of two, may not be -// supported. -ConfigVariableInt jpeg_scale_num -("jpeg-scale-num", 1); -ConfigVariableInt jpeg_scale_denom -("jpeg-scale-denom", 1); - ConfigVariableInt bmp_bpp ("bmp-bpp", 0, PRC_DESC("This controls how many bits per pixel are written out for BMP " diff --git a/panda/src/pnmimagetypes/config_pnmimagetypes.h b/panda/src/pnmimagetypes/config_pnmimagetypes.h index 102ea9d07d..20279f0505 100644 --- a/panda/src/pnmimagetypes/config_pnmimagetypes.h +++ b/panda/src/pnmimagetypes/config_pnmimagetypes.h @@ -52,8 +52,6 @@ extern ConfigVariableBool tga_colormap; extern ConfigVariableBool tga_grayscale; extern ConfigVariableInt jpeg_quality; -extern ConfigVariableInt jpeg_scale_num; -extern ConfigVariableInt jpeg_scale_denom; extern ConfigVariableInt bmp_bpp; diff --git a/panda/src/pnmimagetypes/pnmFileTypeAlias.cxx b/panda/src/pnmimagetypes/pnmFileTypeAlias.cxx index 9bc0e913ef..2f3818005e 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeAlias.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypeAlias.cxx @@ -229,7 +229,7 @@ supports_read_row() const { // if there is an error or end of file. //////////////////////////////////////////////////////////////////// bool PNMFileTypeAlias::Reader:: -read_row(xel *row_data, xelval *) { +read_row(xel *row_data, xelval *, int x_size, int) { if (!is_valid()) { return false; } @@ -239,9 +239,9 @@ read_row(xel *row_data, xelval *) { unsigned char red, grn, blu; x = 0; - while (x < _x_size) { + while (x < x_size) { num = read_uchar_ALIAS(_file); - if (num==0 || x+num > _x_size) { + if (num==0 || x+num > x_size) { return false; } blu = read_uchar_ALIAS(_file); diff --git a/panda/src/pnmimagetypes/pnmFileTypeAlias.h b/panda/src/pnmimagetypes/pnmFileTypeAlias.h index 0bed03a943..584117d229 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeAlias.h +++ b/panda/src/pnmimagetypes/pnmFileTypeAlias.h @@ -49,7 +49,7 @@ public: Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number); virtual bool supports_read_row() const; - virtual bool read_row(xel *array, xelval *alpha); + virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size); }; class Writer : public PNMWriter { diff --git a/panda/src/pnmimagetypes/pnmFileTypeIMG.cxx b/panda/src/pnmimagetypes/pnmFileTypeIMG.cxx index 2cbf49c635..9ce845c30f 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeIMG.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypeIMG.cxx @@ -254,10 +254,10 @@ supports_read_row() const { // if there is an error or end of file. //////////////////////////////////////////////////////////////////// bool PNMFileTypeIMG::Reader:: -read_row(xel *row_data, xelval *) { +read_row(xel *row_data, xelval *, int x_size, int) { int x; xelval red, grn, blu; - for (x = 0; x < _x_size; x++) { + for (x = 0; x < x_size; x++) { red = read_uchar_IMG(_file); grn = read_uchar_IMG(_file); blu = read_uchar_IMG(_file); diff --git a/panda/src/pnmimagetypes/pnmFileTypeIMG.h b/panda/src/pnmimagetypes/pnmFileTypeIMG.h index 8cda5722ac..705bef292b 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeIMG.h +++ b/panda/src/pnmimagetypes/pnmFileTypeIMG.h @@ -49,7 +49,7 @@ public: Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number); virtual bool supports_read_row() const; - virtual bool read_row(xel *array, xelval *alpha); + virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size); }; class Writer : public PNMWriter { diff --git a/panda/src/pnmimagetypes/pnmFileTypeJPG.h b/panda/src/pnmimagetypes/pnmFileTypeJPG.h index a839206f1c..42038e7f5d 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeJPG.h +++ b/panda/src/pnmimagetypes/pnmFileTypeJPG.h @@ -73,6 +73,7 @@ public: Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number); ~Reader(); + virtual void prepare_read(); virtual int read_data(xel *array, xelval *alpha); private: diff --git a/panda/src/pnmimagetypes/pnmFileTypeJPGReader.cxx b/panda/src/pnmimagetypes/pnmFileTypeJPGReader.cxx index 72b6bba477..5618cbf815 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeJPGReader.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypeJPGReader.cxx @@ -295,9 +295,36 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) : * See libjpeg.doc for more info. */ + _num_channels = _cinfo.num_components; + _x_size = (int)_cinfo.image_width; + _y_size = (int)_cinfo.image_height; + _maxval = MAXJSAMPLE; + /* Step 6: set parameters for decompression */ - _cinfo.scale_num = jpeg_scale_num; - _cinfo.scale_denom = jpeg_scale_denom; + _cinfo.scale_num = 1; + _cinfo.scale_denom = 1; +} + +//////////////////////////////////////////////////////////////////// +// Function: PNMFileTypeJPG::Reader::prepare_read +// Access: Public, Virtual +// Description: This method will be called before read_data() or +// read_row() is called. It instructs the reader to +// initialize its data structures as necessary to +// actually perform the read operation. +// +// After this call, _x_size and _y_size should reflect +// the actual size that will be filled by read_data() +// (as possibly modified by set_read_size()). +//////////////////////////////////////////////////////////////////// +void PNMFileTypeJPG::Reader:: +prepare_read() { + if (_has_read_size && _read_x_size != 0 && _read_y_size != 0) { + // Attempt to get the scale close to our target scale. + int x_reduction = _cinfo.image_width / _read_x_size; + int y_reduction = _cinfo.image_height / _read_y_size; + _cinfo.scale_denom = max(min(x_reduction, y_reduction), 1); + } /* Step 7: Start decompressor */ @@ -309,7 +336,6 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) : _num_channels = _cinfo.output_components; _x_size = (int)_cinfo.output_width; _y_size = (int)_cinfo.output_height; - _maxval = MAXJSAMPLE; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pnmimagetypes/pnmFileTypeSGI.h b/panda/src/pnmimagetypes/pnmFileTypeSGI.h index f0e07e2403..d5cc5e4e6c 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeSGI.h +++ b/panda/src/pnmimagetypes/pnmFileTypeSGI.h @@ -53,7 +53,7 @@ public: virtual ~Reader(); virtual bool supports_read_row() const; - virtual bool read_row(xel *array, xelval *alpha); + virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size); typedef struct { long start; /* offset in file */ diff --git a/panda/src/pnmimagetypes/pnmFileTypeSGIReader.cxx b/panda/src/pnmimagetypes/pnmFileTypeSGIReader.cxx index 013703ea06..f364a96a90 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeSGIReader.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypeSGIReader.cxx @@ -182,33 +182,33 @@ supports_read_row() const { // if there is an error or end of file. //////////////////////////////////////////////////////////////////// bool PNMFileTypeSGI::Reader:: -read_row(xel *row_data, xelval *alpha_data) { +read_row(xel *row_data, xelval *alpha_data, int x_size, int y_size) { if (!is_valid()) { return false; } nassertr(current_row >= 0, false); - ScanElem *red = (ScanElem *)alloca(_x_size * sizeof(ScanElem)); - ScanElem *grn = (ScanElem *)alloca(_x_size * sizeof(ScanElem)); - ScanElem *blu = (ScanElem *)alloca(_x_size * sizeof(ScanElem)); - ScanElem *alpha = (ScanElem *)alloca(_x_size * sizeof(ScanElem)); + ScanElem *red = (ScanElem *)alloca(x_size * sizeof(ScanElem)); + ScanElem *grn = (ScanElem *)alloca(x_size * sizeof(ScanElem)); + ScanElem *blu = (ScanElem *)alloca(x_size * sizeof(ScanElem)); + ScanElem *alpha = (ScanElem *)alloca(x_size * sizeof(ScanElem)); - read_channel(_file, _x_size, _y_size, _num_channels, bpc, table, red, + read_channel(_file, x_size, y_size, _num_channels, bpc, table, red, table_start, 0, current_row); if (!is_grayscale()) { - read_channel(_file, _x_size, _y_size, _num_channels, bpc, table, grn, + read_channel(_file, x_size, y_size, _num_channels, bpc, table, grn, table_start, 1, current_row); - read_channel(_file, _x_size, _y_size, _num_channels, bpc, table, blu, + read_channel(_file, x_size, y_size, _num_channels, bpc, table, blu, table_start, 2, current_row); } if (has_alpha()) { - read_channel(_file, _x_size, _y_size, _num_channels, bpc, table, alpha, + read_channel(_file, x_size, y_size, _num_channels, bpc, table, alpha, table_start, _num_channels - 1, current_row); } - for (int x = 0; x < _x_size; x++) { + for (int x = 0; x < x_size; x++) { if (is_grayscale()) { PPM_PUTB(row_data[x], (xelval)red[x]); } else { diff --git a/panda/src/pnmimagetypes/pnmFileTypeSoftImage.cxx b/panda/src/pnmimagetypes/pnmFileTypeSoftImage.cxx index 22eb55dd2a..9423dae8d7 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeSoftImage.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypeSoftImage.cxx @@ -454,31 +454,31 @@ supports_read_row() const { // if there is an error or end of file. //////////////////////////////////////////////////////////////////// bool PNMFileTypeSoftImage::Reader:: -read_row(xel *row_data, xelval *alpha_data) { +read_row(xel *row_data, xelval *alpha_data, int x_size, int) { if (!is_valid()) { return false; } switch (soft_color) { case rgb: - if (!read_scanline(row_data, alpha_data, _x_size, _file, + if (!read_scanline(row_data, alpha_data, x_size, _file, read_rgb, rgb_ctype)) { return false; } break; case rgba: - if (!read_scanline(row_data, alpha_data, _x_size, _file, + if (!read_scanline(row_data, alpha_data, x_size, _file, read_rgba, rgb_ctype)) { return false; } break; case rgb_a: - if (!read_scanline(row_data, alpha_data, _x_size, _file, + if (!read_scanline(row_data, alpha_data, x_size, _file, read_rgb, rgb_ctype)) { return false; } - if (!read_scanline(row_data, alpha_data, _x_size, _file, + if (!read_scanline(row_data, alpha_data, x_size, _file, read_alpha, alpha_ctype)) { return false; } diff --git a/panda/src/pnmimagetypes/pnmFileTypeSoftImage.h b/panda/src/pnmimagetypes/pnmFileTypeSoftImage.h index 401d3963d4..94f28ee7db 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeSoftImage.h +++ b/panda/src/pnmimagetypes/pnmFileTypeSoftImage.h @@ -52,7 +52,7 @@ public: Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number); virtual bool supports_read_row() const; - virtual bool read_row(xel *array, xelval *alpha); + virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size); private: enum { unknown, rgb, rgba, rgb_a } soft_color; diff --git a/panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx b/panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx index 26f467c2a6..77f907f61b 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx +++ b/panda/src/pnmimagetypes/pnmFileTypeTIFF.cxx @@ -592,7 +592,7 @@ supports_read_row() const { // if there is an error or end of file. //////////////////////////////////////////////////////////////////// bool PNMFileTypeTIFF::Reader:: -read_row(xel *row_data, xelval *alpha_data) { +read_row(xel *row_data, xelval *alpha_data, int x_size, int) { if (!is_valid()) { return false; } @@ -639,7 +639,7 @@ read_row(xel *row_data, xelval *alpha_data) { switch ( photomet ) { case PHOTOMETRIC_MINISBLACK: - for ( col = 0; col < _x_size; ++col ) + for ( col = 0; col < x_size; ++col ) { sample = (this->*next_sample)(buf_ptr, bits_left); gray = sample; @@ -661,7 +661,7 @@ read_row(xel *row_data, xelval *alpha_data) { break; case PHOTOMETRIC_MINISWHITE: - for ( col = 0; col < _x_size; ++col ) + for ( col = 0; col < x_size; ++col ) { sample = (this->*next_sample)(buf_ptr, bits_left); gray = _maxval - sample; @@ -685,7 +685,7 @@ read_row(xel *row_data, xelval *alpha_data) { break; case PHOTOMETRIC_PALETTE: - for ( col = 0; col < _x_size; ++col ) + for ( col = 0; col < x_size; ++col ) { sample = (this->*next_sample)(buf_ptr, bits_left); row_data[col] = colormap[sample]; @@ -712,7 +712,7 @@ read_row(xel *row_data, xelval *alpha_data) { break; case PHOTOMETRIC_RGB: - for ( col = 0; col < _x_size; ++col ) { + for ( col = 0; col < x_size; ++col ) { sample = (this->*next_sample)(buf_ptr, bits_left); r = sample; sample = (this->*next_sample)(buf_ptr, bits_left); diff --git a/panda/src/pnmimagetypes/pnmFileTypeTIFF.h b/panda/src/pnmimagetypes/pnmFileTypeTIFF.h index d86631c82b..d44556c6fe 100644 --- a/panda/src/pnmimagetypes/pnmFileTypeTIFF.h +++ b/panda/src/pnmimagetypes/pnmFileTypeTIFF.h @@ -60,7 +60,7 @@ public: virtual ~Reader(); virtual bool supports_read_row() const; - virtual bool read_row(xel *array, xelval *alpha); + virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size); private: xelval next_sample_lt_8(unsigned char *&buf_ptr, int &bits_left) const;