+ fix reading a region from JPEG file
+ re-use jpeg lib structures + avoid resource leaking (store FILE in boost::shared_ptr with custom deleter)
This commit is contained in:
parent
40c01fd0ed
commit
2ca306290a
1 changed files with 40 additions and 44 deletions
|
@ -32,6 +32,7 @@ extern "C"
|
||||||
}
|
}
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/scoped_array.hpp>
|
#include <boost/scoped_array.hpp>
|
||||||
|
|
||||||
// std
|
// std
|
||||||
|
@ -41,13 +42,22 @@ namespace mapnik
|
||||||
{
|
{
|
||||||
class JpegReader : public image_reader, mapnik::noncopyable
|
class JpegReader : public image_reader, mapnik::noncopyable
|
||||||
{
|
{
|
||||||
|
struct file_closer
|
||||||
|
{
|
||||||
|
void operator() (FILE * file)
|
||||||
|
{
|
||||||
|
if (file != 0) fclose(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef boost::shared_ptr<FILE> file_ptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string fileName_;
|
std::string fileName_;
|
||||||
unsigned width_;
|
unsigned width_;
|
||||||
unsigned height_;
|
unsigned height_;
|
||||||
jpeg_decompress_struct cinfo;
|
jpeg_decompress_struct cinfo;
|
||||||
jpeg_error_mgr jerr;
|
jpeg_error_mgr jerr;
|
||||||
FILE *fp;
|
file_ptr file_;
|
||||||
public:
|
public:
|
||||||
explicit JpegReader(std::string const& fileName);
|
explicit JpegReader(std::string const& fileName);
|
||||||
~JpegReader();
|
~JpegReader();
|
||||||
|
@ -74,16 +84,13 @@ JpegReader::JpegReader(std::string const& fileName)
|
||||||
: fileName_(fileName),
|
: fileName_(fileName),
|
||||||
width_(0),
|
width_(0),
|
||||||
height_(0),
|
height_(0),
|
||||||
fp(NULL)
|
file_()
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
JpegReader::~JpegReader() {
|
JpegReader::~JpegReader()
|
||||||
if (fp)
|
{
|
||||||
{
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
jpeg_destroy_decompress(&cinfo);
|
jpeg_destroy_decompress(&cinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,22 +108,28 @@ void JpegReader::on_error_message(j_common_ptr cinfo)
|
||||||
|
|
||||||
void JpegReader::init()
|
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_);
|
if (!fp) throw image_reader_exception("JPEG Reader: cannot open image file " + fileName_);
|
||||||
|
file_ = boost::shared_ptr<FILE>(fp,file_closer());
|
||||||
cinfo.err = jpeg_std_error(&jerr);
|
cinfo.err = jpeg_std_error(&jerr);
|
||||||
jerr.error_exit = on_error;
|
jerr.error_exit = on_error;
|
||||||
jerr.output_message = on_error_message;
|
jerr.output_message = on_error_message;
|
||||||
jpeg_create_decompress(&cinfo);
|
jpeg_create_decompress(&cinfo);
|
||||||
jpeg_stdio_src(&cinfo, fp);
|
jpeg_stdio_src(&cinfo, &*file_);
|
||||||
jpeg_read_header(&cinfo, TRUE);
|
jpeg_read_header(&cinfo, TRUE);
|
||||||
jpeg_start_decompress(&cinfo);
|
jpeg_start_decompress(&cinfo);
|
||||||
width_ = cinfo.output_width;
|
width_ = cinfo.output_width;
|
||||||
height_ = cinfo.output_height;
|
height_ = cinfo.output_height;
|
||||||
// if enabled: "Application transferred too few scanlines"
|
|
||||||
//jpeg_finish_decompress(&cinfo);
|
if (cinfo.out_color_space == JCS_UNKNOWN)
|
||||||
jpeg_destroy_decompress(&cinfo);
|
{
|
||||||
fclose(fp);
|
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
|
unsigned JpegReader::width() const
|
||||||
|
@ -131,59 +144,42 @@ unsigned JpegReader::height() const
|
||||||
|
|
||||||
void JpegReader::read(unsigned x0, unsigned y0, image_data_32& image)
|
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;
|
JSAMPARRAY buffer;
|
||||||
int row_stride;
|
int row_stride;
|
||||||
unsigned char a,r,g,b;
|
unsigned char a,r,g,b;
|
||||||
row_stride = cinfo.output_width * cinfo.output_components;
|
row_stride = cinfo.output_width * cinfo.output_components;
|
||||||
buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
||||||
|
|
||||||
unsigned w = std::min(unsigned(image.width()),width_);
|
unsigned w = std::min(unsigned(image.width()),width_ - x0);
|
||||||
unsigned h = std::min(unsigned(image.height()),height_);
|
unsigned h = std::min(unsigned(image.height()),height_ - y0);
|
||||||
|
|
||||||
boost::scoped_array<unsigned int> out_row(new unsigned int[w]);
|
boost::scoped_array<unsigned int> out_row(new unsigned int[w]);
|
||||||
// TODO - handle x0
|
unsigned row = 0;
|
||||||
for (unsigned i=0;i<h;++i)
|
while (cinfo.output_scanline < cinfo.output_height)
|
||||||
{
|
{
|
||||||
jpeg_read_scanlines(&cinfo, buffer, 1);
|
jpeg_read_scanlines(&cinfo, buffer, 1);
|
||||||
if (i>=y0 && i<h)
|
if (row >= y0 && row < y0 + h)
|
||||||
{
|
{
|
||||||
for (unsigned int x=0; x<w; x++)
|
for (unsigned int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
|
unsigned col = x + x0;
|
||||||
a = 255; // alpha not supported in jpg
|
a = 255; // alpha not supported in jpg
|
||||||
r = buffer[0][cinfo.output_components * x];
|
r = buffer[0][cinfo.output_components * col];
|
||||||
if (cinfo.output_components > 2)
|
if (cinfo.output_components > 2)
|
||||||
{
|
{
|
||||||
g = buffer[0][cinfo.output_components*x+1];
|
g = buffer[0][cinfo.output_components * col + 1];
|
||||||
b = buffer[0][cinfo.output_components*x+2];
|
b = buffer[0][cinfo.output_components * col + 2];
|
||||||
} else {
|
} else {
|
||||||
g = r;
|
g = r;
|
||||||
b = r;
|
b = r;
|
||||||
}
|
}
|
||||||
out_row[x] = color(r, g, b, a).rgba();
|
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);
|
jpeg_destroy_decompress(&cinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue