From 2ca306290aaff1940504c6f037b395a9afe9dc1c Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 8 Apr 2013 15:56:19 +0100 Subject: [PATCH] + fix reading a region from JPEG file + re-use jpeg lib structures + avoid resource leaking (store FILE in boost::shared_ptr with custom deleter) --- src/jpeg_reader.cpp | 84 +++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/src/jpeg_reader.cpp b/src/jpeg_reader.cpp index 05dbd66fe..e0240f7df 100644 --- a/src/jpeg_reader.cpp +++ b/src/jpeg_reader.cpp @@ -32,6 +32,7 @@ extern "C" } // boost +#include #include // std @@ -41,13 +42,22 @@ namespace mapnik { class JpegReader : public image_reader, mapnik::noncopyable { + struct file_closer + { + void operator() (FILE * file) + { + if (file != 0) fclose(file); + } + }; + typedef boost::shared_ptr file_ptr; + private: std::string fileName_; unsigned width_; unsigned height_; jpeg_decompress_struct cinfo; jpeg_error_mgr jerr; - FILE *fp; + file_ptr file_; public: explicit JpegReader(std::string const& fileName); ~JpegReader(); @@ -74,16 +84,13 @@ JpegReader::JpegReader(std::string const& fileName) : fileName_(fileName), width_(0), height_(0), - fp(NULL) + file_() { init(); } -JpegReader::~JpegReader() { - if (fp) - { - fclose(fp); - } +JpegReader::~JpegReader() +{ jpeg_destroy_decompress(&cinfo); } @@ -101,22 +108,28 @@ void JpegReader::on_error_message(j_common_ptr cinfo) void JpegReader::init() { - fp = fopen(fileName_.c_str(),"rb"); + FILE * fp = fopen(fileName_.c_str(),"rb"); if (!fp) throw image_reader_exception("JPEG Reader: cannot open image file " + fileName_); - + file_ = boost::shared_ptr(fp,file_closer()); cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = on_error; jerr.output_message = on_error_message; jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo, fp); + jpeg_stdio_src(&cinfo, &*file_); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); width_ = cinfo.output_width; height_ = cinfo.output_height; - // if enabled: "Application transferred too few scanlines" - //jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - fclose(fp); + + if (cinfo.out_color_space == JCS_UNKNOWN) + { + throw image_reader_exception("JPEG Reader: failed to read unknown color space in " + fileName_); + } + if (cinfo.output_width == 0 || cinfo.output_height == 0) + { + jpeg_destroy_decompress (&cinfo); + throw image_reader_exception("JPEG Reader: failed to read image size of " + fileName_); + } } unsigned JpegReader::width() const @@ -131,59 +144,42 @@ unsigned JpegReader::height() const void JpegReader::read(unsigned x0, unsigned y0, image_data_32& image) { - fp = fopen(fileName_.c_str(),"rb"); - if (!fp) throw image_reader_exception("JPEG Reader: cannot open image file " + fileName_); - - cinfo.err = jpeg_std_error(&jerr); - - jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo, fp); - - jpeg_read_header(&cinfo, TRUE); - if (cinfo.out_color_space == JCS_UNKNOWN) - throw image_reader_exception("JPEG Reader: failed to read unknown color space in " + fileName_); - - jpeg_start_decompress(&cinfo); - - if (cinfo.output_width == 0) { - jpeg_destroy_decompress (&cinfo); - throw image_reader_exception("JPEG Reader: failed to read image size of " + fileName_); - } - JSAMPARRAY buffer; int row_stride; unsigned char a,r,g,b; row_stride = cinfo.output_width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); - unsigned w = std::min(unsigned(image.width()),width_); - unsigned h = std::min(unsigned(image.height()),height_); + unsigned w = std::min(unsigned(image.width()),width_ - x0); + unsigned h = std::min(unsigned(image.height()),height_ - y0); boost::scoped_array out_row(new unsigned int[w]); - // TODO - handle x0 - for (unsigned i=0;i=y0 && i= y0 && row < y0 + h) { - for (unsigned int x=0; x 2) { - g = buffer[0][cinfo.output_components*x+1]; - b = buffer[0][cinfo.output_components*x+2]; + g = buffer[0][cinfo.output_components * col + 1]; + b = buffer[0][cinfo.output_components * col + 2]; } else { g = r; b = r; } out_row[x] = color(r, g, b, a).rgba(); } - image.setRow(i-y0, out_row.get(), w); + image.setRow(row - y0, out_row.get(), w); } + ++row; } - jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); } + }