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/array.hpp>
#include <boost/iostreams/stream.hpp>
// stl
#include <fstream>
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
{
typedef T buffer_policy_type;
private:
struct config_guard
{
config_guard(WebPDecoderConfig & config)
@ -53,13 +102,13 @@ private:
}
WebPDecoderConfig & config_;
};
uint8_t const* data_;
std::unique_ptr<buffer_policy_type> buffer_;
size_t size_;
unsigned width_;
unsigned height_;
public:
explicit webp_reader(char const* data, std::size_t size);
explicit webp_reader(std::string const& filename);
~webp_reader();
unsigned width() const;
unsigned height() const;
@ -73,33 +122,70 @@ namespace
{
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 registered2 = register_image_reader("webp", create_webp_reader2);
}
// ctor
webp_reader::webp_reader(char const* data, std::size_t size)
: data_(reinterpret_cast<uint8_t const*>(data)),
size_(size),
template <typename T>
webp_reader<T>::webp_reader(char const* data, std::size_t size)
: buffer_(new buffer_policy_type(reinterpret_cast<uint8_t const*>(data), size)),
width_(0),
height_(0)
{
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
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;
if (!WebPGetInfo(data_, size_, &width, &height))
if (!WebPGetInfo(buffer_->data(), buffer_->size(), &width, &height))
{
throw image_reader_exception("WEBP reader: WebPGetInfo failed");
}
@ -107,17 +193,20 @@ void webp_reader::init()
height_ = height;
}
unsigned webp_reader::width() const
template <typename T>
unsigned webp_reader<T>::width() const
{
return width_;
}
unsigned webp_reader::height() const
template <typename T>
unsigned webp_reader<T>::height() const
{
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;
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_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");
}
@ -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.size = image.width() * image.height() * 4;
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");
}