webp_reader : implement reading from file

This commit is contained in:
artemp 2013-04-16 10:48:21 +01:00
parent b8637a900e
commit 1b90879d12

View file

@ -34,14 +34,63 @@ extern "C"
#include <boost/iostreams/device/file.hpp> #include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/device/array.hpp> #include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp> #include <boost/iostreams/stream.hpp>
// stl
#include <fstream>
namespace mapnik namespace mapnik
{ {
struct external_buffer_policy
{
external_buffer_policy( uint8_t const* data, std::size_t size)
: data_(data),
size_(size) {}
uint8_t const* data() const
{
return data_;
}
std::size_t size() const
{
return size_;
}
uint8_t const* data_;
std::size_t size_;
};
struct internal_buffer_policy
{
internal_buffer_policy(std::size_t size)
: data_((size!=0) ? static_cast<uint8_t*>(::operator new(sizeof(uint8_t) * size)) : 0),
size_(size)
{}
uint8_t * data() const
{
return data_;
}
std::size_t size() const
{
return size_;
}
~internal_buffer_policy()
{
::operator delete(data_), data_=0;
}
uint8_t * data_;
std::size_t size_;
};
template <typename T>
class webp_reader : public image_reader class webp_reader : public image_reader
{ {
typedef T buffer_policy_type;
private: private:
struct config_guard struct config_guard
{ {
config_guard(WebPDecoderConfig & config) config_guard(WebPDecoderConfig & config)
@ -53,13 +102,13 @@ private:
} }
WebPDecoderConfig & config_; WebPDecoderConfig & config_;
}; };
std::unique_ptr<buffer_policy_type> buffer_;
uint8_t const* data_;
size_t size_; size_t size_;
unsigned width_; unsigned width_;
unsigned height_; unsigned height_;
public: public:
explicit webp_reader(char const* data, std::size_t size); explicit webp_reader(char const* data, std::size_t size);
explicit webp_reader(std::string const& filename);
~webp_reader(); ~webp_reader();
unsigned width() const; unsigned width() const;
unsigned height() const; unsigned height() const;
@ -73,33 +122,70 @@ namespace
{ {
image_reader* create_webp_reader(char const * data, std::size_t size) image_reader* create_webp_reader(char const * data, std::size_t size)
{ {
return new webp_reader(data, size); return new webp_reader<external_buffer_policy>(data, size);
} }
image_reader* create_webp_reader2(std::string const& filename)
{
return new webp_reader<internal_buffer_policy>(filename);
}
const bool registered = register_image_reader("webp", create_webp_reader); const bool registered = register_image_reader("webp", create_webp_reader);
const bool registered2 = register_image_reader("webp", create_webp_reader2);
} }
// ctor // ctor
webp_reader::webp_reader(char const* data, std::size_t size) template <typename T>
: data_(reinterpret_cast<uint8_t const*>(data)), webp_reader<T>::webp_reader(char const* data, std::size_t size)
size_(size), : buffer_(new buffer_policy_type(reinterpret_cast<uint8_t const*>(data), size)),
width_(0), width_(0),
height_(0) height_(0)
{ {
init(); init();
} }
template <typename T>
webp_reader<T>::webp_reader(std::string const& filename)
: buffer_(0),
size_(0),
width_(0),
height_(0)
{
std::ifstream file(filename.c_str(), std::ios::binary);
if (!file)
{
throw image_reader_exception("WEBP: Can't read file:" + filename);
}
std::streampos beg = file.tellg();
file.seekg (0, std::ios::end);
std::streampos end = file.tellg();
std::size_t file_size = end - beg;
file.seekg (0, std::ios::beg);
std::unique_ptr<buffer_policy_type> buffer(new buffer_policy_type(file_size));
file.read(reinterpret_cast<char*>(buffer->data()), buffer->size());
if (!file)
{
throw image_reader_exception("WEBP: Failed to read:" + filename);
}
buffer_ = std::move(buffer);
init();
}
// dtor // dtor
webp_reader::~webp_reader() template <typename T>
webp_reader<T>::~webp_reader()
{ {
// //
} }
void webp_reader::init() template <typename T>
void webp_reader<T>::init()
{ {
int width, height; int width, height;
if (!WebPGetInfo(data_, size_, &width, &height)) if (!WebPGetInfo(buffer_->data(), buffer_->size(), &width, &height))
{ {
throw image_reader_exception("WEBP reader: WebPGetInfo failed"); throw image_reader_exception("WEBP reader: WebPGetInfo failed");
} }
@ -107,17 +193,20 @@ void webp_reader::init()
height_ = height; height_ = height;
} }
unsigned webp_reader::width() const template <typename T>
unsigned webp_reader<T>::width() const
{ {
return width_; return width_;
} }
unsigned webp_reader::height() const template <typename T>
unsigned webp_reader<T>::height() const
{ {
return height_; return height_;
} }
void webp_reader::read(unsigned x0, unsigned y0,image_data_32& image) template <typename T>
void webp_reader<T>::read(unsigned x0, unsigned y0,image_data_32& image)
{ {
WebPDecoderConfig config; WebPDecoderConfig config;
config_guard guard(config); config_guard guard(config);
@ -132,7 +221,7 @@ void webp_reader::read(unsigned x0, unsigned y0,image_data_32& image)
config.options.crop_width = std::min(width_ - x0, image.width()); config.options.crop_width = std::min(width_ - x0, image.width());
config.options.crop_height = std::min(height_ - y0, image.height()); config.options.crop_height = std::min(height_ - y0, image.height());
if (WebPGetFeatures(data_, size_, &config.input) != VP8_STATUS_OK) if (WebPGetFeatures(buffer_->data(), buffer_->size(), &config.input) != VP8_STATUS_OK)
{ {
throw image_reader_exception("WEBP reader: WebPGetFeatures failed"); throw image_reader_exception("WEBP reader: WebPGetFeatures failed");
} }
@ -142,7 +231,7 @@ void webp_reader::read(unsigned x0, unsigned y0,image_data_32& image)
config.output.u.RGBA.stride = 4 * image.width(); config.output.u.RGBA.stride = 4 * image.width();
config.output.u.RGBA.size = image.width() * image.height() * 4; config.output.u.RGBA.size = image.width() * image.height() * 4;
config.output.is_external_memory = 1; config.output.is_external_memory = 1;
if (WebPDecode(data_, size_, &config) != VP8_STATUS_OK) if (WebPDecode(buffer_->data(), buffer_->size(), &config) != VP8_STATUS_OK)
{ {
throw image_reader_exception("WEBP reader: WebPDecode failed"); throw image_reader_exception("WEBP reader: WebPDecode failed");
} }