2010-06-03 23:24:58 +02:00
|
|
|
/*****************************************************************************
|
2012-02-02 02:53:35 +01:00
|
|
|
*
|
2010-06-03 23:24:58 +02:00
|
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
|
|
*
|
2011-10-23 15:04:25 +02:00
|
|
|
* Copyright (C) 2011 Artem Pavlenko
|
2010-06-03 23:24:58 +02:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
// mapnik
|
|
|
|
#include <mapnik/image_reader.hpp>
|
|
|
|
#include <mapnik/color.hpp>
|
2012-12-17 03:19:52 +01:00
|
|
|
#include <mapnik/noncopyable.hpp>
|
2010-06-03 23:24:58 +02:00
|
|
|
|
|
|
|
// jpeg
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
#include <jpeglib.h>
|
|
|
|
}
|
|
|
|
|
2010-06-04 00:43:25 +02:00
|
|
|
// boost
|
2013-04-08 16:56:19 +02:00
|
|
|
#include <boost/shared_ptr.hpp>
|
2010-06-03 23:24:58 +02:00
|
|
|
#include <boost/scoped_array.hpp>
|
|
|
|
|
2011-11-08 19:34:00 +01:00
|
|
|
// std
|
|
|
|
#include <cstdio>
|
2010-06-04 00:43:25 +02:00
|
|
|
|
2010-06-03 23:24:58 +02:00
|
|
|
namespace mapnik
|
|
|
|
{
|
2013-04-09 12:34:20 +02:00
|
|
|
class jpeg_reader : public image_reader
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2013-04-10 03:36:02 +02:00
|
|
|
struct jpeg_file_guard
|
2013-04-08 16:56:19 +02:00
|
|
|
{
|
2013-04-10 03:36:02 +02:00
|
|
|
jpeg_file_guard(FILE * fd)
|
|
|
|
: fd_(fd) {}
|
|
|
|
|
|
|
|
~jpeg_file_guard()
|
|
|
|
{
|
|
|
|
if (fd_) fclose(fd_);
|
|
|
|
}
|
|
|
|
FILE * fd_;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct jpeg_info_guard
|
|
|
|
{
|
|
|
|
jpeg_info_guard(jpeg_decompress_struct * cinfo)
|
|
|
|
: i_(cinfo) {}
|
|
|
|
|
|
|
|
~jpeg_info_guard()
|
|
|
|
{
|
|
|
|
jpeg_destroy_decompress(i_);
|
|
|
|
}
|
|
|
|
jpeg_decompress_struct * i_;
|
2013-04-08 16:56:19 +02:00
|
|
|
};
|
|
|
|
|
2012-02-02 02:53:35 +01:00
|
|
|
private:
|
2013-04-09 12:34:20 +02:00
|
|
|
std::string file_name_;
|
2012-02-02 02:53:35 +01:00
|
|
|
unsigned width_;
|
|
|
|
unsigned height_;
|
|
|
|
public:
|
2013-04-09 12:34:20 +02:00
|
|
|
explicit jpeg_reader(std::string const& fileName);
|
|
|
|
~jpeg_reader();
|
2012-02-02 02:53:35 +01:00
|
|
|
unsigned width() const;
|
|
|
|
unsigned height() const;
|
2012-10-05 01:07:24 +02:00
|
|
|
inline bool premultiplied_alpha() const { return true; }
|
2012-02-02 02:53:35 +01:00
|
|
|
void read(unsigned x,unsigned y,image_data_32& image);
|
|
|
|
private:
|
|
|
|
void init();
|
2013-03-26 02:29:29 +01:00
|
|
|
static void on_error(j_common_ptr cinfo);
|
|
|
|
static void on_error_message(j_common_ptr cinfo);
|
2012-02-02 02:53:35 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2013-04-09 12:34:20 +02:00
|
|
|
image_reader* create_jpeg_reader(std::string const& file)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2013-04-09 12:34:20 +02:00
|
|
|
return new jpeg_reader(file);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2013-04-09 12:34:20 +02:00
|
|
|
const bool registered = register_image_reader("jpeg",create_jpeg_reader);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-06-03 23:24:58 +02:00
|
|
|
|
2013-04-09 12:34:20 +02:00
|
|
|
jpeg_reader::jpeg_reader(std::string const& fileName)
|
|
|
|
: file_name_(fileName),
|
2012-02-02 02:53:35 +01:00
|
|
|
width_(0),
|
2013-04-10 03:36:02 +02:00
|
|
|
height_(0)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
2010-06-03 23:24:58 +02:00
|
|
|
|
2013-04-10 03:36:02 +02:00
|
|
|
jpeg_reader::~jpeg_reader() {}
|
2013-03-26 02:29:29 +01:00
|
|
|
|
2013-04-09 12:34:20 +02:00
|
|
|
void jpeg_reader::on_error(j_common_ptr cinfo)
|
2013-03-26 02:29:29 +01:00
|
|
|
{
|
2013-04-10 03:36:02 +02:00
|
|
|
//(*cinfo->err->output_message)(cinfo);
|
|
|
|
//jpeg_destroy(cinfo);
|
2013-03-26 02:29:29 +01:00
|
|
|
throw image_reader_exception("JPEG Reader: libjpeg could not read image");
|
|
|
|
}
|
|
|
|
|
2013-04-09 12:34:20 +02:00
|
|
|
void jpeg_reader::on_error_message(j_common_ptr cinfo)
|
2013-03-26 02:29:29 +01:00
|
|
|
{
|
|
|
|
// used to supress jpeg from printing to stderr
|
|
|
|
}
|
2010-06-03 23:24:58 +02:00
|
|
|
|
2013-04-09 12:34:20 +02:00
|
|
|
void jpeg_reader::init()
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2013-04-09 12:34:20 +02:00
|
|
|
FILE * fp = fopen(file_name_.c_str(),"rb");
|
|
|
|
if (!fp) throw image_reader_exception("JPEG Reader: cannot open image file " + file_name_);
|
2013-04-10 03:36:02 +02:00
|
|
|
jpeg_file_guard guard(fp);
|
|
|
|
jpeg_decompress_struct cinfo;
|
|
|
|
jpeg_info_guard iguard(&cinfo);
|
|
|
|
jpeg_error_mgr jerr;
|
2012-02-02 02:53:35 +01:00
|
|
|
cinfo.err = jpeg_std_error(&jerr);
|
2013-03-26 02:29:29 +01:00
|
|
|
jerr.error_exit = on_error;
|
|
|
|
jerr.output_message = on_error_message;
|
2012-02-02 02:53:35 +01:00
|
|
|
jpeg_create_decompress(&cinfo);
|
2013-04-10 03:36:02 +02:00
|
|
|
jpeg_stdio_src(&cinfo, fp);
|
|
|
|
int ret = jpeg_read_header(&cinfo, TRUE);
|
|
|
|
if (ret != JPEG_HEADER_OK) throw image_reader_exception("JPEG Reader: failed to read header in " + file_name_);
|
2012-02-02 02:53:35 +01:00
|
|
|
jpeg_start_decompress(&cinfo);
|
|
|
|
width_ = cinfo.output_width;
|
|
|
|
height_ = cinfo.output_height;
|
2013-04-08 16:56:19 +02:00
|
|
|
|
|
|
|
if (cinfo.out_color_space == JCS_UNKNOWN)
|
|
|
|
{
|
2013-04-09 12:34:20 +02:00
|
|
|
throw image_reader_exception("JPEG Reader: failed to read unknown color space in " + file_name_);
|
2013-04-08 16:56:19 +02:00
|
|
|
}
|
|
|
|
if (cinfo.output_width == 0 || cinfo.output_height == 0)
|
|
|
|
{
|
2013-04-09 12:34:20 +02:00
|
|
|
throw image_reader_exception("JPEG Reader: failed to read image size of " + file_name_);
|
2013-04-08 16:56:19 +02:00
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2010-06-03 23:24:58 +02:00
|
|
|
|
2013-04-09 12:34:20 +02:00
|
|
|
unsigned jpeg_reader::width() const
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
|
|
|
return width_;
|
|
|
|
}
|
2010-06-03 23:24:58 +02:00
|
|
|
|
2013-04-09 12:34:20 +02:00
|
|
|
unsigned jpeg_reader::height() const
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
|
|
|
return height_;
|
|
|
|
}
|
2010-06-03 23:24:58 +02:00
|
|
|
|
2013-04-09 12:34:20 +02:00
|
|
|
void jpeg_reader::read(unsigned x0, unsigned y0, image_data_32& image)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
2013-04-10 03:36:02 +02:00
|
|
|
FILE * fp = fopen(file_name_.c_str(),"rb");
|
|
|
|
if (!fp) throw image_reader_exception("JPEG Reader: cannot open image file " + file_name_);
|
|
|
|
jpeg_file_guard guard(fp);
|
|
|
|
jpeg_decompress_struct cinfo;
|
|
|
|
jpeg_info_guard iguard(&cinfo);
|
|
|
|
jpeg_error_mgr jerr;
|
|
|
|
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);
|
|
|
|
int ret = jpeg_read_header(&cinfo, TRUE);
|
|
|
|
if (ret != JPEG_HEADER_OK) throw image_reader_exception("JPEG Reader: failed to read header in " + file_name_);
|
|
|
|
jpeg_start_decompress(&cinfo);
|
2012-02-02 02:53:35 +01:00
|
|
|
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);
|
|
|
|
|
2013-04-08 16:56:19 +02:00
|
|
|
unsigned w = std::min(unsigned(image.width()),width_ - x0);
|
|
|
|
unsigned h = std::min(unsigned(image.height()),height_ - y0);
|
2012-02-02 02:53:35 +01:00
|
|
|
|
|
|
|
boost::scoped_array<unsigned int> out_row(new unsigned int[w]);
|
2013-04-08 16:56:19 +02:00
|
|
|
unsigned row = 0;
|
|
|
|
while (cinfo.output_scanline < cinfo.output_height)
|
2012-02-02 02:53:35 +01:00
|
|
|
{
|
|
|
|
jpeg_read_scanlines(&cinfo, buffer, 1);
|
2013-04-08 16:56:19 +02:00
|
|
|
if (row >= y0 && row < y0 + h)
|
2010-06-03 23:24:58 +02:00
|
|
|
{
|
2013-04-08 16:56:19 +02:00
|
|
|
for (unsigned int x = 0; x < w; ++x)
|
2010-06-03 23:24:58 +02:00
|
|
|
{
|
2013-04-08 16:56:19 +02:00
|
|
|
unsigned col = x + x0;
|
2012-02-02 02:53:35 +01:00
|
|
|
a = 255; // alpha not supported in jpg
|
2013-04-08 16:56:19 +02:00
|
|
|
r = buffer[0][cinfo.output_components * col];
|
2012-02-02 02:53:35 +01:00
|
|
|
if (cinfo.output_components > 2)
|
2010-06-03 23:24:58 +02:00
|
|
|
{
|
2013-04-08 16:56:19 +02:00
|
|
|
g = buffer[0][cinfo.output_components * col + 1];
|
|
|
|
b = buffer[0][cinfo.output_components * col + 2];
|
2012-02-02 02:53:35 +01:00
|
|
|
} else {
|
|
|
|
g = r;
|
|
|
|
b = r;
|
2010-06-03 23:24:58 +02:00
|
|
|
}
|
2012-02-02 02:53:35 +01:00
|
|
|
out_row[x] = color(r, g, b, a).rgba();
|
|
|
|
}
|
2013-04-08 16:56:19 +02:00
|
|
|
image.setRow(row - y0, out_row.get(), w);
|
2010-06-03 23:24:58 +02:00
|
|
|
}
|
2013-04-08 16:56:19 +02:00
|
|
|
++row;
|
2010-06-03 23:24:58 +02:00
|
|
|
}
|
2013-04-10 03:36:02 +02:00
|
|
|
jpeg_finish_decompress(&cinfo);
|
2012-02-02 02:53:35 +01:00
|
|
|
}
|
2013-04-08 16:56:19 +02:00
|
|
|
|
2010-06-03 23:24:58 +02:00
|
|
|
}
|