+ 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
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
|
||||
// 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> 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<FILE>(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<unsigned int> out_row(new unsigned int[w]);
|
||||
// TODO - handle x0
|
||||
for (unsigned i=0;i<h;++i)
|
||||
unsigned row = 0;
|
||||
while (cinfo.output_scanline < cinfo.output_height)
|
||||
{
|
||||
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
|
||||
r = buffer[0][cinfo.output_components * x];
|
||||
r = buffer[0][cinfo.output_components * col];
|
||||
if (cinfo.output_components > 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue