From a141c5c27dcfeb7b1a8dd97ead6e63c444545654 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 19 Jul 2013 01:09:17 -0400 Subject: [PATCH] webp encoding/decoding support - refs #1955 --- INSTALL.md | 16 +- SConstruct | 22 +- include/mapnik/image_util.hpp | 7 + include/mapnik/image_view.hpp | 7 +- include/mapnik/webp_io.hpp | 130 ++++++++++ src/build.py | 9 + src/image_reader.cpp | 8 + src/image_util.cpp | 91 +++++++ src/webp_reader.cpp | 239 ++++++++++++++++++ tests/cpp_tests/data/blank.webp | 0 tests/cpp_tests/image_io_test.cpp | 14 + .../encoding-opts/blank-webp+q=64.webp | Bin 0 -> 240 bytes .../support/encoding-opts/blank-webp.webp | Bin 0 -> 240 bytes .../encoding-opts/solid-webp+q=64.webp | Bin 0 -> 240 bytes .../support/encoding-opts/solid-webp.webp | Bin 0 -> 240 bytes .../images/support/transparency/white0.webp | Bin 0 -> 358 bytes tests/python_tests/webp_encoding_test.py | 98 +++++++ 17 files changed, 630 insertions(+), 11 deletions(-) create mode 100644 include/mapnik/webp_io.hpp create mode 100644 src/webp_reader.cpp create mode 100644 tests/cpp_tests/data/blank.webp create mode 100644 tests/python_tests/images/support/encoding-opts/blank-webp+q=64.webp create mode 100644 tests/python_tests/images/support/encoding-opts/blank-webp.webp create mode 100644 tests/python_tests/images/support/encoding-opts/solid-webp+q=64.webp create mode 100644 tests/python_tests/images/support/encoding-opts/solid-webp.webp create mode 100644 tests/python_tests/images/support/transparency/white0.webp create mode 100644 tests/python_tests/webp_encoding_test.py diff --git a/INSTALL.md b/INSTALL.md index bde1b50ef..e7b2aeddd 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -48,22 +48,26 @@ Mapnik Core depends on: - regex (optionally built with icu regex support) - program_options (optionally for mapnik command line programs) * libicuuc >= 4.0 (ideally >= 4.2) - International Components for Unicode - * libpng >= 1.2.x - PNG graphics - * libjpeg - JPEG graphics - * libtiff - TIFF graphics * libz - Zlib compression * libfreetype - Freetype2 for font support (Install requires freetype-config) * libxml2 - XML parsing (Install requires xml2-config) - * libproj - PROJ.4 projection library + +Mapnik Core optionally depends on: + + * libpng >= 1.2.x - PNG graphics (Default enabled, if found) + * libjpeg - JPEG graphics (Default enabled, if found) + * libtiff - TIFF graphics (Default enabled, if found) + * libwebp - WEBP graphics (Default enabled, if found) + * libproj - PROJ.4 projection library (Default enabled, if found) Mapnik Python bindings depend on: * Python 2.5-2.7 or >= 3.2 * Boost python -Note: Python3k is supported, see: https://github.com/mapnik/mapnik/wiki/Python3k +Note: Python 3.x is supported, see: https://github.com/mapnik/mapnik/wiki/Python3k -Optional dependencies: +Additional optional dependencies: * Cairo >= 1.6.0 - Graphics library for output formats like PDF, PS, and SVG - pkg-config - Required for building with cairo support diff --git a/SConstruct b/SConstruct index 7eca8390e..aea96662a 100644 --- a/SConstruct +++ b/SConstruct @@ -73,6 +73,7 @@ pretty_dep_names = { 'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES', 'tiff':'TIFF C library | configure with TIFF_LIBS & TIFF_INCLUDES', 'png':'PNG C library | configure with PNG_LIBS & PNG_INCLUDES', + 'webp':'WEBP C library | configure with WEBP_LIBS & WEBP_INCLUDES', 'icuuc':'ICU C++ library | configure with ICU_LIBS & ICU_INCLUDES or use ICU_LIB_NAME to specify custom lib name | more info: http://site.icu-project.org/', 'z':'Z compression library | more info: http://www.zlib.net/', 'm':'Basic math library, part of C++ stlib', @@ -325,6 +326,9 @@ opts.AddVariables( BoolVariable('TIFF', 'Build Mapnik with TIFF read and write support', 'True'), PathVariable('TIFF_INCLUDES', 'Search path for libtiff include files', '/usr/include', PathVariable.PathAccept), PathVariable('TIFF_LIBS', 'Search path for libtiff library files', '/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), + BoolVariable('WEBP', 'Build Mapnik with WEBP read', 'True'), + PathVariable('WEBP_INCLUDES', 'Search path for libwebp include files', '/usr/include', PathVariable.PathAccept), + PathVariable('WEBP_LIBS','Search path for libwebp library files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), BoolVariable('PROJ', 'Build Mapnik with proj4 support to enable transformations between many different projections', 'True'), PathVariable('PROJ_INCLUDES', 'Search path for PROJ.4 include files', '/usr/include', PathVariable.PathAccept), PathVariable('PROJ_LIBS', 'Search path for PROJ.4 library files', '/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), @@ -1185,7 +1189,7 @@ if not preconfigured: if env['JPEG']: env.Append(CPPDEFINES = '-DHAVE_JPEG') - LIBSHEADERS.append(['jpeg', ['stdio.h', 'jpeglib.h'], True,'C']) + LIBSHEADERS.append(['jpeg', ['stdio.h', 'jpeglib.h'], False,'C']) inc_path = env['%s_INCLUDES' % 'JPEG'] lib_path = env['%s_LIBS' % 'JPEG'] env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) @@ -1195,7 +1199,7 @@ if not preconfigured: if env['PROJ']: env.Append(CPPDEFINES = '-DMAPNIK_USE_PROJ4') - LIBSHEADERS.append(['proj', 'proj_api.h', True,'C']) + LIBSHEADERS.append(['proj', 'proj_api.h', False,'C']) inc_path = env['%s_INCLUDES' % 'PROJ'] lib_path = env['%s_LIBS' % 'PROJ'] env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) @@ -1205,7 +1209,7 @@ if not preconfigured: if env['PNG']: env.Append(CPPDEFINES = '-DHAVE_PNG') - LIBSHEADERS.append(['png', 'png.h', True,'C']) + LIBSHEADERS.append(['png', 'png.h', False,'C']) inc_path = env['%s_INCLUDES' % 'PNG'] lib_path = env['%s_LIBS' % 'PNG'] env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) @@ -1213,9 +1217,19 @@ if not preconfigured: else: env['SKIPPED_DEPS'].extend(['png']) + if env['WEBP']: + env.Append(CPPDEFINES = '-DHAVE_WEBP') + LIBSHEADERS.append(['webp', 'webp/decode.h', False,'C']) + inc_path = env['%s_INCLUDES' % 'WEBP'] + lib_path = env['%s_LIBS' % 'WEBP'] + env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) + env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) + else: + env['SKIPPED_DEPS'].extend(['webp']) + if env['TIFF']: env.Append(CPPDEFINES = '-DHAVE_TIFF') - LIBSHEADERS.append(['tiff', 'tiff.h', True,'C']) + LIBSHEADERS.append(['tiff', 'tiff.h', False,'C']) inc_path = env['%s_INCLUDES' % 'TIFF'] lib_path = env['%s_LIBS' % 'TIFF'] env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 56c0fc847..8aa2415a3 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -147,6 +147,12 @@ inline bool is_ps (std::string const& filename) return boost::algorithm::iends_with(filename,std::string(".ps")); } +inline bool is_webp (std::string const& filename) +{ + return boost::algorithm::iends_with(filename,std::string(".webp")); +} + + inline boost::optional type_from_filename(std::string const& filename) { @@ -157,6 +163,7 @@ inline boost::optional type_from_filename(std::string const& filena if (is_pdf(filename)) return result_type("pdf"); if (is_svg(filename)) return result_type("svg"); if (is_ps(filename)) return result_type("ps"); + if (is_webp(filename)) return result_type("webp"); return result_type(); } diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 4b788871f..b7bf54985 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -88,6 +88,12 @@ public: { return data_.getRow(row + y_) + x_; } + + inline char const* getBytes() const + { + return reinterpret_cast(&data_); + } + inline T& data() { return data_; @@ -107,4 +113,3 @@ private: } #endif // MAPNIK_IMAGE_VIEW_HPP - diff --git a/include/mapnik/webp_io.hpp b/include/mapnik/webp_io.hpp new file mode 100644 index 000000000..80c5473a3 --- /dev/null +++ b/include/mapnik/webp_io.hpp @@ -0,0 +1,130 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2013 Artem Pavlenko + * + * 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 + * + *****************************************************************************/ + +#ifndef MAPNIK_WEBP_IO_HPP +#define MAPNIK_WEBP_IO_HPP + +#include + +#include +#include +#include + + +namespace mapnik { + +template +int webp_stream_write(const uint8_t* data, size_t data_size, const WebPPicture* picture) +{ + T* out = static_cast(picture->custom_ptr); + out->write(reinterpret_cast(data), data_size); + return true; +} + +std::string webp_encoding_error(WebPEncodingError error) { + std::ostringstream os; + switch (error) { + case VP8_ENC_ERROR_OUT_OF_MEMORY: os << "memory error allocating objects"; break; + case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY: os << "memory error while flushing bits"; break; + case VP8_ENC_ERROR_NULL_PARAMETER: os << "a pointer parameter is NULL"; break; + case VP8_ENC_ERROR_INVALID_CONFIGURATION: os << "configuration is invalid"; break; + case VP8_ENC_ERROR_BAD_DIMENSION: os << "picture has invalid width/height"; break; + case VP8_ENC_ERROR_PARTITION0_OVERFLOW: os << "partition is bigger than 512k"; break; + case VP8_ENC_ERROR_PARTITION_OVERFLOW: os << "partition is bigger than 16M"; break; + case VP8_ENC_ERROR_BAD_WRITE: os << "error while flushing bytes"; break; + case VP8_ENC_ERROR_FILE_TOO_BIG: os << "file is bigger than 4G"; break; + default: os << "unknown error (" << error << ")"; break; + } + os << " during encoding"; + return os.str(); +} + +template +void save_as_webp(T1& file, + float quality, + int method, + int lossless, + int image_hint, + T2 const& image) +{ + WebPConfig config; + if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality)) + { + throw std::runtime_error("version mismatch"); + } + + // Add additional tuning + if (method >= 0) config.method = method; + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 2 + config.lossless = lossless; + config.image_hint = static_cast(image_hint); + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support lossless flag) + #else + #warning "compiling against webp that does not support lossless flag" + #endif + #endif + + bool valid = WebPValidateConfig(&config); + if (!valid) { + throw std::runtime_error("Invalid configuration"); + } + + WebPPicture pic; + if (!WebPPictureInit(&pic)) + { + throw std::runtime_error("version mismatch"); + } + pic.width = image.width(); + pic.height = image.height(); + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 2 + pic.use_argb = 1; + #endif + if (!WebPPictureAlloc(&pic)) + { + throw std::runtime_error("memory error"); + } + + int stride = sizeof(typename T2::pixel_type) * image.width(); + uint8_t const* bytes = reinterpret_cast(image.getBytes()); + int ok = WebPPictureImportRGBA(&pic, bytes, stride); + if (!ok) + { + throw std::runtime_error(webp_encoding_error(pic.error_code)); + } + + pic.writer = webp_stream_write; + pic.custom_ptr = &file; + + ok = WebPEncode(&config, &pic); + WebPPictureFree(&pic); + if (!ok) + { + throw std::runtime_error(webp_encoding_error(pic.error_code)); + } + + file.flush(); +} +} + +#endif // MAPNIK_WEBP_IO_HPP diff --git a/src/build.py b/src/build.py index 14fa224fe..91dbe5f5c 100644 --- a/src/build.py +++ b/src/build.py @@ -68,6 +68,9 @@ if env['PNG']: if env['TIFF']: lib_env['LIBS'].append('tiff') +if env['WEBP']: + lib_env['LIBS'].append('webp') + if env['JPEG']: lib_env['LIBS'].append('jpeg') @@ -269,6 +272,12 @@ if env['PNG']: png_reader.cpp """) +if env['WEBP']: + source += Split( + """ + webp_reader.cpp + """) + # agg backend source += Split( """ diff --git a/src/image_reader.cpp b/src/image_reader.cpp index af98b6f0e..539221040 100644 --- a/src/image_reader.cpp +++ b/src/image_reader.cpp @@ -59,6 +59,14 @@ inline boost::optional type_from_bytes(char const* data, size_t siz } } + if (size>=12) + { + if (data[0] == 'R' && data[1] == 'I' && data[2] == 'F' && data[3] == 'F' && + data[8] == 'W' && data[9] == 'E' && data[10] == 'B' && data[11] == 'P') + { + return result_type("webp"); + } + } return result_type(); } diff --git a/src/image_util.cpp b/src/image_util.cpp index efe61c766..7d6759243 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -40,6 +40,10 @@ extern "C" #include #endif +#if defined(HAVE_WEBP) +#include +#endif + #include #include #include @@ -237,6 +241,73 @@ void handle_png_options(std::string const& type, } #endif + +#if defined(HAVE_WEBP) +void handle_webp_options(std::string const& type, + double & quality, + int & method, + int & lossless, + int & image_hint + ) +{ + if (type == "webp") + { + return; + } + if (type.length() > 4){ + boost::char_separator sep(":"); + boost::tokenizer< boost::char_separator > tokens(type, sep); + BOOST_FOREACH(std::string t, tokens) + { + if (boost::algorithm::starts_with(t, "quality=")) + { + std::string val = t.substr(8); + if (!val.empty()) + { + if (!mapnik::util::string2double(val,quality) || quality < 0.0 || quality > 100.0) + { + throw ImageWriterException("invalid webp quality: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "method=")) + { + std::string val = t.substr(7); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,method) || method < 0 || method > 6) + { + throw ImageWriterException("invalid webp method: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "lossless=")) + { + std::string val = t.substr(9); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,lossless) || lossless < 0 || lossless > 1) + { + throw ImageWriterException("invalid webp lossless: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "image_hint=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,image_hint) || image_hint < 0 || image_hint > 3) + { + throw ImageWriterException("invalid webp image_hint: '" + val + "'"); + } + } + } + } + } +} +#endif + template void save_to_stream(T const& image, std::ostream & stream, @@ -369,6 +440,26 @@ void save_to_stream(T const& image, save_as_jpeg(stream, quality, image); #else throw ImageWriterException("jpeg output is not enabled in your build of Mapnik"); +#endif + } + else if (boost::algorithm::starts_with(t, "webp")) + { +#if defined(HAVE_WEBP) + double quality = 90.0; // 0 lowest, 100 highest + int method = 3; // 0 if fastest, 6 slowest + int lossless = 0; // Lossless encoding (0=lossy(default), 1=lossless). + int image_hint = 3; // used when lossless=1 + /* + WEBP_HINT_DEFAULT = 0, // default preset. + WEBP_HINT_PICTURE, // digital picture, like portrait, inner shot + WEBP_HINT_PHOTO, // outdoor photograph, with natural lighting + WEBP_HINT_GRAPH, // Discrete tone image (graph, map-tile etc). + WEBP_HINT_LAST + */ + handle_webp_options(t,quality,method,lossless, image_hint); + save_as_webp(stream, static_cast(quality), method, lossless, image_hint, image); +#else + throw ImageWriterException("webp output is not enabled in your build of Mapnik"); #endif } else throw ImageWriterException("unknown file type: " + type); diff --git a/src/webp_reader.cpp b/src/webp_reader.cpp new file mode 100644 index 000000000..29f87dbd2 --- /dev/null +++ b/src/webp_reader.cpp @@ -0,0 +1,239 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2013 Artem Pavlenko + * + * 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 +#include + +extern "C" +{ +#include +#include +} + +// boost +#include +#include +#include +// stl +#include + +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(::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 +class webp_reader : public image_reader +{ + typedef T buffer_policy_type; +private: + struct config_guard + { + config_guard(WebPDecoderConfig & config) + : config_(config) {} + + ~config_guard() + { + WebPFreeDecBuffer(&config_.output); + } + WebPDecoderConfig & config_; + }; + std::auto_ptr 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; + bool premultiplied_alpha() const { return false; } + void read(unsigned x,unsigned y,image_data_32& image); +private: + void init(); +}; + +namespace +{ +image_reader* create_webp_reader(char const * data, std::size_t size) +{ + return new webp_reader(data, size); +} + +image_reader* create_webp_reader2(std::string const& filename) +{ + return new webp_reader(filename); +} + + +const bool registered = register_image_reader("webp", create_webp_reader); +const bool registered2 = register_image_reader("webp", create_webp_reader2); + +} + +// ctor +template +webp_reader::webp_reader(char const* data, std::size_t size) + : buffer_(new buffer_policy_type(reinterpret_cast(data), size)), + width_(0), + height_(0) +{ + init(); +} + +template +webp_reader::webp_reader(std::string const& filename) + : buffer_(), + 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); + buffer_ = std::auto_ptr(new buffer_policy_type(file_size)); + file.read(reinterpret_cast(buffer_->data()), buffer_->size()); + if (!file) + { + throw image_reader_exception("WEBP: Failed to read:" + filename); + } + init(); +} + + +// dtor +template +webp_reader::~webp_reader() +{ + // +} + +template +void webp_reader::init() +{ + int width, height; + if (!WebPGetInfo(buffer_->data(), buffer_->size(), &width, &height)) + { + throw image_reader_exception("WEBP reader: WebPGetInfo failed"); + } + width_ = width; + height_ = height; +} + +template +unsigned webp_reader::width() const +{ + return width_; +} + +template +unsigned webp_reader::height() const +{ + return height_; +} + +template +void webp_reader::read(unsigned x0, unsigned y0,image_data_32& image) +{ + WebPDecoderConfig config; + config_guard guard(config); + if (!WebPInitDecoderConfig(&config)) + { + throw image_reader_exception("WEBP reader: WebPInitDecoderConfig failed"); + } + + config.options.use_cropping = 1; + config.options.crop_left = x0; + config.options.crop_top = y0; + config.options.crop_width = std::min(width_ - x0, image.width()); + config.options.crop_height = std::min(height_ - y0, image.height()); + + if (WebPGetFeatures(buffer_->data(), buffer_->size(), &config.input) != VP8_STATUS_OK) + { + throw image_reader_exception("WEBP reader: WebPGetFeatures failed"); + } + + config.output.colorspace = MODE_RGBA; + config.output.u.RGBA.rgba = (uint8_t *)image.getBytes(); + 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(buffer_->data(), buffer_->size(), &config) != VP8_STATUS_OK) + { + throw image_reader_exception("WEBP reader: WebPDecode failed"); + } +} + +} diff --git a/tests/cpp_tests/data/blank.webp b/tests/cpp_tests/data/blank.webp new file mode 100644 index 000000000..e69de29bb diff --git a/tests/cpp_tests/image_io_test.cpp b/tests/cpp_tests/image_io_test.cpp index 06c229bbf..549378ba4 100644 --- a/tests/cpp_tests/image_io_test.cpp +++ b/tests/cpp_tests/image_io_test.cpp @@ -67,6 +67,20 @@ int main(int argc, char** argv) BOOST_TEST( true ); } + should_throw = "./tests/cpp_tests/data/blank.webp"; + BOOST_TEST( mapnik::util::exists( should_throw ) ); + type = mapnik::type_from_filename(should_throw); + BOOST_TEST( type ); + try + { + std::auto_ptr reader(mapnik::get_image_reader(should_throw,*type)); + BOOST_TEST( false ); + } + catch (std::exception const&) + { + BOOST_TEST( true ); + } + should_throw = "./tests/data/images/xcode-CgBI.png"; BOOST_TEST( mapnik::util::exists( should_throw ) ); type = mapnik::type_from_filename(should_throw); diff --git a/tests/python_tests/images/support/encoding-opts/blank-webp+q=64.webp b/tests/python_tests/images/support/encoding-opts/blank-webp+q=64.webp new file mode 100644 index 0000000000000000000000000000000000000000..ce65bf5dfa5acc01a4afc89b04198d3192ef82aa GIT binary patch literal 240 zcmWIYbaQ*bz`zjh>J$(bU=hIuWD5ZCe=u_N3GfgB@)+3#1po3gXk7aLU*zKdFaQ5B zGcW*EE35;`T@YfJ%c#Y`$iQf4DADbrv`BH{7X}SxmMz;0c1QFs$TXg0JN4fU4;Bx% z$(F|NpH}X&I6BYKq_BJT;;xz7r#^e}SX})Z^XZ7AXD>Q@x@K5hQrIqLe`)*vsm~7l zH+PrVxywA~_s_VzKEw10zA{PAUOZZs3pV5A-v+Sq0Gq8nF?VGWkM@6A3p9O${n?Ah b^zwRd+x-ily|^c`f#Ki(577!hcR~OFQ95Rw literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/encoding-opts/blank-webp.webp b/tests/python_tests/images/support/encoding-opts/blank-webp.webp new file mode 100644 index 0000000000000000000000000000000000000000..ce65bf5dfa5acc01a4afc89b04198d3192ef82aa GIT binary patch literal 240 zcmWIYbaQ*bz`zjh>J$(bU=hIuWD5ZCe=u_N3GfgB@)+3#1po3gXk7aLU*zKdFaQ5B zGcW*EE35;`T@YfJ%c#Y`$iQf4DADbrv`BH{7X}SxmMz;0c1QFs$TXg0JN4fU4;Bx% z$(F|NpH}X&I6BYKq_BJT;;xz7r#^e}SX})Z^XZ7AXD>Q@x@K5hQrIqLe`)*vsm~7l zH+PrVxywA~_s_VzKEw10zA{PAUOZZs3pV5A-v+Sq0Gq8nF?VGWkM@6A3p9O${n?Ah b^zwRd+x-ily|^c`f#Ki(577!hcR~OFQ95Rw literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/encoding-opts/solid-webp+q=64.webp b/tests/python_tests/images/support/encoding-opts/solid-webp+q=64.webp new file mode 100644 index 0000000000000000000000000000000000000000..ce65bf5dfa5acc01a4afc89b04198d3192ef82aa GIT binary patch literal 240 zcmWIYbaQ*bz`zjh>J$(bU=hIuWD5ZCe=u_N3GfgB@)+3#1po3gXk7aLU*zKdFaQ5B zGcW*EE35;`T@YfJ%c#Y`$iQf4DADbrv`BH{7X}SxmMz;0c1QFs$TXg0JN4fU4;Bx% z$(F|NpH}X&I6BYKq_BJT;;xz7r#^e}SX})Z^XZ7AXD>Q@x@K5hQrIqLe`)*vsm~7l zH+PrVxywA~_s_VzKEw10zA{PAUOZZs3pV5A-v+Sq0Gq8nF?VGWkM@6A3p9O${n?Ah b^zwRd+x-ily|^c`f#Ki(577!hcR~OFQ95Rw literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/encoding-opts/solid-webp.webp b/tests/python_tests/images/support/encoding-opts/solid-webp.webp new file mode 100644 index 0000000000000000000000000000000000000000..ce65bf5dfa5acc01a4afc89b04198d3192ef82aa GIT binary patch literal 240 zcmWIYbaQ*bz`zjh>J$(bU=hIuWD5ZCe=u_N3GfgB@)+3#1po3gXk7aLU*zKdFaQ5B zGcW*EE35;`T@YfJ%c#Y`$iQf4DADbrv`BH{7X}SxmMz;0c1QFs$TXg0JN4fU4;Bx% z$(F|NpH}X&I6BYKq_BJT;;xz7r#^e}SX})Z^XZ7AXD>Q@x@K5hQrIqLe`)*vsm~7l zH+PrVxywA~_s_VzKEw10zA{PAUOZZs3pV5A-v+Sq0Gq8nF?VGWkM@6A3p9O${n?Ah b^zwRd+x-ily|^c`f#Ki(577!hcR~OFQ95Rw literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/transparency/white0.webp b/tests/python_tests/images/support/transparency/white0.webp new file mode 100644 index 0000000000000000000000000000000000000000..81c926c2373dea3c47ce2320dd8091de39cbd723 GIT binary patch literal 358 zcmV-s0h#_%Nk&Fq0RRA3MM6+kP&il$0000G000300093006|PpNF)FN01Y1?5FkTr z$Ph9A!6_gRpa}nmTTn#*v%JIq?S8z$|Lq~R*T~B}pb|3-xfu;lT1NBq^s-Pnlip}HfHb=p#DMfFV`*fLoe=BoT zVTy-;R6UizjKzF^^8nXWd^U%&t8_0KRaeNoX!#cKDiEvV9>>VHfl!5C81_Czyb6Rn zM^$&>-VOl8F6@+q&xcM2$#hoxa~M+!FKFl5FO3Xs8tOPMF;MU7hqAamP)Z))TBUA_ zV%Oooes6WrssKjOu1IVszBSB;^0r#mlrVe%0RH@PPx@c%SbVkr!)E#c;@{JP