Merge branch 'master' into csv-disk-index

This commit is contained in:
artemp 2015-09-17 14:54:25 +01:00
commit c7177e2ef4
14 changed files with 319 additions and 104 deletions

View file

@ -14,9 +14,29 @@ Released: YYYY XX, 2015
#### Summary
- Visual tests: new command line arguments `--agg`, `--cairo`, `--svg`, `--grid` for selecting renderers (https://github.com/mapnik/mapnik/pull/3074)
- Visual tests: new command line argument `--scale-factor` or abbreviated `-s` for setting scale factor (https://github.com/mapnik/mapnik/pull/3074)
## 3.0.5
Released: September 16, 2015
(Packaged from 165c704)
#### Summary
- `scale-hsla` image filter: parameters are no longer limited by interval \[0, 1\] (https://github.com/mapnik/mapnik/pull/3054)
- Windows: Fixed SVG file loading from unicode paths
- `colorize-alpha` image filter: fixed normalization of color components (https://github.com/mapnik/mapnik/pull/3058)
- `colorize-alpha` image filter: added support for transparent colors (https://github.com/mapnik/mapnik/pull/3061)
- Enable reading optional `MAPNIK_LOG_FORMAT` environment variable(https://github.com/mapnik/mapnik/commit/6d1ffc8a93008b8c0a89d87d68b59afb2cb3757f)
- CSV.input uses memory mapped file by default on *nix.
- Updated bundled fonts to the latest version
- Topojson.input - fixed geometry_index logic which was causing missing features
- Fixed SVG file loading from unicode paths (https://github.com/mapnik/node-mapnik/issues/517)
- CSV.input - improved support for LF/CR/CRLF line endings on all platforms (https://github.com/mapnik/mapnik/issues/3065)
- Revive `zero allocation image interface` and add unit tests
- Benchmark: use return values of test runner.
## 3.0.4

View file

@ -34,24 +34,20 @@ namespace detail {
struct MAPNIK_DECL buffer
{
explicit buffer(std::size_t size);
explicit buffer(unsigned char* data, std::size_t size);
buffer(buffer && rhs) noexcept;
buffer(buffer const& rhs);
~buffer();
buffer& operator=(buffer rhs);
inline bool operator!() const
{
return (data_ == nullptr)? true : false;
}
void swap(buffer & rhs);
unsigned char* data();
unsigned char const* data() const;
std::size_t size() const;
inline bool operator!() const {return (data_ == nullptr)? true : false;}
inline unsigned char* data() {return data_;}
inline unsigned char const* data() const {return data_;}
inline std::size_t size() const {return size_;}
private:
void swap(buffer & rhs);
std::size_t size_;
unsigned char* data_;
bool owns_;
};
template <std::size_t max_size>
@ -76,6 +72,8 @@ class image
public:
using pixel = T;
using pixel_type = typename T::type;
using iterator = pixel_type*;
using const_iterator = pixel_type const*;
static constexpr image_dtype dtype = T::id;
static constexpr std::size_t pixel_size = sizeof(pixel_type);
private:
@ -93,6 +91,11 @@ public:
bool initialize = true,
bool premultiplied = false,
bool painted = false);
image(int width,
int height,
unsigned char* data,
bool premultiplied = false,
bool painted = false);
image(image<T> const& rhs);
image(image<T> && rhs) noexcept;
image<T>& operator=(image<T> rhs);
@ -109,6 +112,12 @@ public:
void set(pixel_type const& t);
pixel_type const* data() const;
pixel_type* data();
// simple iterator inteface
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
//
unsigned char const* bytes() const;
unsigned char* bytes();
pixel_type const* get_row(std::size_t row) const;

View file

@ -505,6 +505,7 @@ void apply_filter(Src & src, colorize_alpha const& op)
uint8_t & a = get_color(src_it[x], alpha_t());
if ( a > 0)
{
a = (c.alpha() * a + 255) >> 8;
r = (c.red() * a + 255) >> 8;
g = (c.green() * a + 255) >> 8;
b = (c.blue() * a + 255) >> 8;
@ -549,6 +550,7 @@ void apply_filter(Src & src, colorize_alpha const& op)
if ( a > 0)
{
agg::rgba8 c = grad_lut[a];
a = (c.a * a + 255) >> 8;
r = (c.r * a + 255) >> 8;
g = (c.g * a + 255) >> 8;
b = (c.b * a + 255) >> 8;

View file

@ -77,6 +77,16 @@ image<T>::image()
painted_(false)
{}
template <typename T>
image<T>::image(int width, int height, unsigned char* data, bool premultiplied, bool painted)
: dimensions_(width, height),
buffer_(data, width * height * sizeof(pixel_size)),
pData_(reinterpret_cast<pixel_type*>(buffer_.data())),
offset_(0.0),
scaling_(1.0),
premultiplied_alpha_(premultiplied),
painted_(painted) {}
template <typename T>
image<T>::image(int width, int height, bool initialize, bool premultiplied, bool painted)
: dimensions_(width, height),
@ -101,18 +111,17 @@ image<T>::image(image<T> const& rhs)
offset_(rhs.offset_),
scaling_(rhs.scaling_),
premultiplied_alpha_(rhs.premultiplied_alpha_),
painted_(rhs.painted_)
{}
painted_(rhs.painted_) {}
template <typename T>
image<T>::image(image<T> && rhs) noexcept
: dimensions_(std::move(rhs.dimensions_)),
buffer_(std::move(rhs.buffer_)),
pData_(reinterpret_cast<pixel_type*>(buffer_.data())),
offset_(rhs.offset_),
scaling_(rhs.scaling_),
premultiplied_alpha_(rhs.premultiplied_alpha_),
painted_(rhs.painted_)
buffer_(std::move(rhs.buffer_)),
pData_(reinterpret_cast<pixel_type*>(buffer_.data())),
offset_(rhs.offset_),
scaling_(rhs.scaling_),
premultiplied_alpha_(rhs.premultiplied_alpha_),
painted_(rhs.painted_)
{
rhs.dimensions_ = { 0, 0 };
rhs.pData_ = nullptr;
@ -216,6 +225,20 @@ inline unsigned char* image<T>::bytes()
return buffer_.data();
}
// iterator interface
template <typename T>
inline typename image<T>::iterator image<T>::begin() { return pData_; }
template <typename T>
inline typename image<T>::iterator image<T>::end() { return pData_ + dimensions_.width() * dimensions_.height(); }
template <typename T>
inline typename image<T>::const_iterator image<T>::begin() const { return pData_; }
template <typename T>
inline typename image<T>::const_iterator image<T>::end() const{ return pData_ + dimensions_.width() * dimensions_.height(); }
template <typename T>
inline typename image<T>::pixel_type const* image<T>::get_row(std::size_t row) const
{

View file

@ -36,27 +36,38 @@ namespace detail
// BUFFER
buffer::buffer(std::size_t size)
: size_(size),
data_(static_cast<unsigned char*>(size_ != 0 ? ::operator new(size_) : nullptr))
data_(static_cast<unsigned char*>(size_ != 0 ? ::operator new(size_) : nullptr)),
owns_(true)
{}
buffer::buffer(unsigned char* data, std::size_t size)
: size_(size),
data_(data),
owns_(false)
{}
// move
buffer::buffer(buffer && rhs) noexcept
: size_(std::move(rhs.size_)),
data_(std::move(rhs.data_))
: size_(rhs.size_),
data_(rhs.data_),
owns_(rhs.owns_)
{
rhs.size_ = 0;
rhs.data_ = nullptr;
rhs.owns_ = false;
}
// copy
buffer::buffer(buffer const& rhs)
: size_(rhs.size_),
data_(static_cast<unsigned char*>(size_ != 0 ? ::operator new(size_) : nullptr))
data_(static_cast<unsigned char*>(size_ != 0 ? ::operator new(size_) : nullptr)),
owns_(true)
{
if (data_) std::copy(rhs.data_, rhs.data_ + rhs.size_, data_);
}
buffer::~buffer()
{
::operator delete(data_);
if (owns_) ::operator delete(data_);
}
buffer& buffer::operator=(buffer rhs)
@ -69,21 +80,7 @@ void buffer::swap(buffer & rhs)
{
std::swap(size_, rhs.size_);
std::swap(data_, rhs.data_);
}
unsigned char* buffer::data()
{
return data_;
}
unsigned char const* buffer::data() const
{
return data_;
}
std::size_t buffer::size() const
{
return size_;
std::swap(owns_, rhs.owns_);
}
template struct MAPNIK_DECL image_dimensions<65535>;

@ -1 +1 @@
Subproject commit 89aac0440103fc19ff05bbf29e3efa473db20f3d
Subproject commit 79597b73f0255f00dd0f9c276e031223540fba78

View file

@ -10,7 +10,7 @@
TEST_CASE("image class") {
SECTION("test gray16") {
const mapnik::image_gray16 im(4,4);
mapnik::image_gray16 im2(im);
mapnik::image_gray16 im3(5,5);
@ -20,11 +20,11 @@ SECTION("test gray16") {
CHECK_FALSE(im2 == im3);
CHECK(im < im3);
CHECK_FALSE(im < im2);
// Check that width is correct
CHECK(im.width() == 4);
CHECK(im2.width() == 4);
// Check that height is correct
CHECK(im.height() == 4);
CHECK(im2.height() == 4);
@ -40,11 +40,11 @@ SECTION("test gray16") {
// Check that size is correct
CHECK(im.size() == 32);
CHECK(im2.size() == 32);
// Check that row_size is correct
CHECK(im.row_size() == 8);
CHECK(im2.row_size() == 8);
// Check that get_premultiplied is correct
CHECK_FALSE(im.get_premultiplied());
CHECK_FALSE(im2.get_premultiplied());
@ -52,7 +52,7 @@ SECTION("test gray16") {
// Check that set premultiplied works
im2.set_premultiplied(true);
CHECK(im2.get_premultiplied());
// Check that painted is correct
CHECK_FALSE(im.painted());
CHECK_FALSE(im2.painted());
@ -64,15 +64,15 @@ SECTION("test gray16") {
// Check that offset is correct
CHECK(im.get_offset() == 0.0);
CHECK(im2.get_offset() == 0.0);
// Check that set offset works
im2.set_offset(2.3);
CHECK(im2.get_offset() == 2.3);
// Check that scaling is correct
CHECK(im.get_scaling() == 1.0);
CHECK(im2.get_scaling() == 1.0);
// Check that set scaling works
im2.set_scaling(1.1);
CHECK(im2.get_scaling() == 1.1);
@ -140,7 +140,7 @@ SECTION("test gray16") {
CHECK(im2(0,0) == 30);
CHECK(im2(0,1) == 514);
CHECK(im2(1,1) == 50);
} // END SECTION
SECTION("image_null")
@ -149,11 +149,11 @@ SECTION("image_null")
const mapnik::image_null im_null2(2,2); // Actually doesn't really set any size
mapnik::image_null im_null3(im_null2);
mapnik::image_null im_null4(std::move(im_null3));
// All nulls are equal
CHECK(im_null == im_null4);
CHECK(im_null == im_null2);
// No null is greater
CHECK_FALSE(im_null < im_null4);
CHECK_FALSE(im_null < im_null2);
@ -289,5 +289,85 @@ SECTION("Image Buffer")
} // END SECTION
} // END TEST CASE
SECTION("Image copy/move")
{
mapnik::detail::buffer buf(16 * 16 * 4); // large enough to hold 16*16 RGBA image
CHECK(buf.size() == 16 * 16 * 4);
// fill buffer with 0xff
std::fill(buf.data(), buf.data() + buf.size(), 0xff);
// move buffer
mapnik::detail::buffer buf2(std::move(buf));
CHECK (buf.size() == 0);
CHECK (buf.data() == nullptr);
mapnik::image_rgba8 im(16, 16, buf2.data()); // shallow copy
std::size_t count = 0;
for (auto const& pixel : im)
{
// expect rgba(255,255,255,1.0)
CHECK( sizeof(pixel) == sizeof(mapnik::image_rgba8::pixel_type));
CHECK( pixel == 0xffffffff);
++count;
}
CHECK( count == im.width() * im.height());
CHECK( buf2.size() == im.width() * im.height() * sizeof( mapnik::image_rgba8::pixel_type));
// mutate buffer
// fill buffer with 0x7f - semi-transparent grey
std::fill(buf2.data(), buf2.data() + buf2.size(), 0x7f);
for (auto const& pixel : im)
{
// expect rgba(127,127,127,0.5)
CHECK( pixel == 0x7f7f7f7f);
}
// mutate image directly (buf)
for (auto & pixel : im)
{
pixel = mapnik::color(0,255,0).rgba(); // green
}
// move
mapnik::image_rgba8 im2(std::move(im));
CHECK (im.data() == nullptr);
CHECK (im.bytes() == nullptr);
CHECK (im.width() == 0);
CHECK (im.height() == 0);
for (auto const& pixel : im2)
{
// expect `green`
CHECK( pixel == mapnik::color(0,255,0).rgba());
}
// deep copy
mapnik::image_rgba8 im3(im2); // allocates new internal buffer
for (auto & pixel : im3)
{
// expect `green`
CHECK( pixel == mapnik::color(0,255,0).rgba());
// mutate
pixel = mapnik::color(255,0,0).rgba(); //red
}
// im2 (green)
for (auto const& pixel : im2)
{
// expect `green`
CHECK( pixel == mapnik::color(0,255,0).rgba());
}
//buf2 still holds green pixels
CHECK(buf2.size() == 16 * 16 * 4);
unsigned char* itr = buf2.data();
unsigned char* end = itr + buf2.size();
count = 0;
for ( ;itr!= end; ++itr)
{
CHECK( *itr == ((count++ % 2 == 0) ? 0 : 0xff)); // green
}
}
} // END TEST CASE

View file

@ -348,6 +348,46 @@ SECTION("test colorize-alpha - two color") {
} // END SECTION
SECTION("test colorize-alpha - one color with transparency") {
mapnik::image_rgba8 im(3,3);
mapnik::fill(im,mapnik::color("#0000ffaa"));
mapnik::set_pixel(im, 1, 1, mapnik::color("#aaaaaaaa"));
mapnik::filter::filter_image(im, "colorize-alpha(#0000ff99)");
CHECK(im(0,0) == 0x66660000);
CHECK(im(0,1) == 0x66660000);
CHECK(im(0,2) == 0x66660000);
CHECK(im(1,0) == 0x66660000);
CHECK(im(1,1) == 0x66660000);
CHECK(im(1,2) == 0x66660000);
CHECK(im(2,0) == 0x66660000);
CHECK(im(2,1) == 0x66660000);
CHECK(im(2,2) == 0x66660000);
} // END SECTION
SECTION("test colorize-alpha - two color with transparency") {
mapnik::image_rgba8 im(3,3);
mapnik::fill(im,mapnik::color("#0000ffaa"));
mapnik::set_pixel(im, 1, 1, mapnik::color("#aaaaaaaa"));
mapnik::filter::filter_image(im, "colorize-alpha(#0000ff00,#00ff00ff)");
CHECK(im(0,0) == 0x70264a00);
CHECK(im(0,1) == 0x70264a00);
CHECK(im(0,2) == 0x70264a00);
CHECK(im(1,0) == 0x70264a00);
CHECK(im(1,1) == 0x70264a00);
CHECK(im(1,2) == 0x70264a00);
CHECK(im(2,0) == 0x70264a00);
CHECK(im(2,1) == 0x70264a00);
CHECK(im(2,2) == 0x70264a00);
} // END SECTION
SECTION("test color-blind-protanope") {
mapnik::image_rgba8 im(2,2);

View file

@ -21,6 +21,11 @@ SECTION("readers") {
boost::optional<std::string> type;
try
{
mapnik::image_rgba8 im_og;
auto im_size = mapnik::image_rgba8::pixel_size * im_og.width() * im_og.height();
mapnik::detail::buffer buf(im_og.bytes(), im_size);
mapnik::image_rgba8 im2(im_og.width(), im_og.height(), buf.data());
CHECK( im2.bytes() == im_og.bytes() );
#if defined(HAVE_JPEG)
should_throw = "./test/data/images/blank.jpg";
REQUIRE( mapnik::util::exists( should_throw ) );

View file

@ -33,6 +33,7 @@
#include <mapnik/map.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/util/variant.hpp>
#include <mapnik/agg_renderer.hpp>
#if defined(GRID_RENDERER)
#include <mapnik/grid/grid_renderer.hpp>
@ -326,11 +327,23 @@ private:
}
const Renderer ren;
boost::filesystem::path const & output_dir;
boost::filesystem::path const & reference_dir;
const boost::filesystem::path output_dir;
const boost::filesystem::path reference_dir;
const bool overwrite;
};
using renderer_type = mapnik::util::variant<renderer<agg_renderer>
#if defined(HAVE_CAIRO)
,renderer<cairo_renderer>
#endif
#if defined(SVG_RENDERER)
,renderer<svg_renderer>
#endif
#if defined(GRID_RENDERER)
,renderer<grid_renderer>
#endif
>;
}
#endif

View file

@ -43,11 +43,50 @@ log_levels_map log_levels
};
#endif
using namespace visual_tests;
namespace po = boost::program_options;
runner::renderer_container create_renderers(po::variables_map const & args,
boost::filesystem::path const & output_dir,
bool append_all = false)
{
boost::filesystem::path reference_dir(args["images-dir"].as<std::string>());
bool overwrite = args.count("overwrite");
runner::renderer_container renderers;
if (append_all || args.count(agg_renderer::name))
{
renderers.emplace_back(renderer<agg_renderer>(output_dir, reference_dir, overwrite));
}
#if defined(HAVE_CAIRO)
if (append_all || args.count(cairo_renderer::name))
{
renderers.emplace_back(renderer<cairo_renderer>(output_dir, reference_dir, overwrite));
}
#endif
#if defined(SVG_RENDERER)
if (append_all || args.count(svg_renderer::name))
{
renderers.emplace_back(renderer<svg_renderer>(output_dir, reference_dir, overwrite));
}
#endif
#if defined(GRID_RENDERER)
if (append_all || args.count(grid_renderer::name))
{
renderers.emplace_back(renderer<grid_renderer>(output_dir, reference_dir, overwrite));
}
#endif
if (renderers.empty())
{
return create_renderers(args, output_dir, true);
}
return renderers;
}
int main(int argc, char** argv)
{
using namespace visual_tests;
namespace po = boost::program_options;
po::options_description desc("visual test runner");
desc.add_options()
("help,h", "produce usage message")
@ -68,6 +107,17 @@ int main(int argc, char** argv)
("log", po::value<std::string>()->default_value(std::find_if(log_levels.begin(), log_levels.end(),
[](log_levels_map::value_type const & level) { return level.second == mapnik::logger::get_severity(); } )->first),
"log level (debug, warn, error, none)")
#endif
("scale-factor,s", po::value<std::vector<double>>()->default_value({ 1.0, 2.0 }, "1.0, 2.0"), "scale factor")
(agg_renderer::name, "render with AGG renderer")
#if defined(HAVE_CAIRO)
(cairo_renderer::name, "render with Cairo renderer")
#endif
#if defined(SVG_RENDERER)
(svg_renderer::name, "render with SVG renderer")
#endif
#if defined(GRID_RENDERER)
(grid_renderer::name, "render with Grid renderer")
#endif
;
@ -107,13 +157,15 @@ int main(int argc, char** argv)
output_dir /= boost::filesystem::unique_path();
}
config defaults;
defaults.scales = vm["scale-factor"].as<std::vector<double>>();
runner run(vm["styles-dir"].as<std::string>(),
output_dir,
vm["images-dir"].as<std::string>(),
vm.count("overwrite"),
defaults,
vm["iterations"].as<std::size_t>(),
vm["limit"].as<std::size_t>(),
vm["jobs"].as<std::size_t>());
vm["jobs"].as<std::size_t>(),
create_renderers(vm, output_dir));
bool show_duration = vm.count("duration");
report_type report(vm.count("verbose") ? report_type((console_report(show_duration))) : report_type((console_short_report(show_duration))));
result_list results;

View file

@ -126,29 +126,17 @@ private:
};
runner::runner(runner::path_type const & styles_dir,
runner::path_type const & output_dir,
runner::path_type const & reference_dir,
bool overwrite,
config const & defaults,
std::size_t iterations,
std::size_t fail_limit,
std::size_t jobs)
std::size_t jobs,
runner::renderer_container const & renderers)
: styles_dir_(styles_dir),
output_dir_(output_dir),
reference_dir_(reference_dir),
defaults_(defaults),
jobs_(jobs),
iterations_(iterations),
fail_limit_(fail_limit),
renderers_{ renderer<agg_renderer>(output_dir_, reference_dir_, overwrite)
#if defined(HAVE_CAIRO)
,renderer<cairo_renderer>(output_dir_, reference_dir_, overwrite)
#endif
#if defined(SVG_RENDERER)
,renderer<svg_renderer>(output_dir_, reference_dir_, overwrite)
#endif
#if defined(GRID_RENDERER)
,renderer<grid_renderer>(output_dir_, reference_dir_, overwrite)
#endif
}
renderers_(renderers)
{
}
@ -225,7 +213,6 @@ result_list runner::test_range(files_iterator begin,
std::reference_wrapper<report_type> report,
std::reference_wrapper<std::atomic<std::size_t>> fail_count) const
{
config defaults;
result_list results;
for (runner::files_iterator i = begin; i != end; i++)
@ -235,7 +222,7 @@ result_list runner::test_range(files_iterator begin,
{
try
{
result_list r = test_one(file, defaults, report, fail_count.get());
result_list r = test_one(file, report, fail_count.get());
std::move(r.begin(), r.end(), std::back_inserter(results));
}
catch (std::exception const& ex)
@ -260,10 +247,10 @@ result_list runner::test_range(files_iterator begin,
}
result_list runner::test_one(runner::path_type const& style_path,
config cfg,
report_type & report,
std::atomic<std::size_t> & fail_count) const
{
config cfg(defaults_);
mapnik::Map map(cfg.sizes.front().width, cfg.sizes.front().height);
result_list results;

View file

@ -23,8 +23,6 @@
#ifndef VISUAL_TEST_RUNNER_HPP
#define VISUAL_TEST_RUNNER_HPP
#include <mapnik/util/variant.hpp>
#include "config.hpp"
#include "report.hpp"
#include "renderer.hpp"
@ -35,28 +33,18 @@ namespace visual_tests
class runner
{
using renderer_type = mapnik::util::variant<renderer<agg_renderer>
#if defined(HAVE_CAIRO)
,renderer<cairo_renderer>
#endif
#if defined(SVG_RENDERER)
,renderer<svg_renderer>
#endif
#if defined(GRID_RENDERER)
,renderer<grid_renderer>
#endif
>;
using path_type = boost::filesystem::path;
using files_iterator = std::vector<path_type>::const_iterator;
public:
using renderer_container = std::vector<renderer_type>;
runner(path_type const & styles_dir,
path_type const & output_dir,
path_type const & reference_dir,
bool overwrite,
config const & cfg,
std::size_t iterations,
std::size_t fail_limit,
std::size_t jobs);
std::size_t jobs,
renderer_container const & renderers);
result_list test_all(report_type & report) const;
result_list test(std::vector<std::string> const & style_names, report_type & report) const;
@ -68,18 +56,17 @@ private:
std::reference_wrapper<report_type> report,
std::reference_wrapper<std::atomic<std::size_t>> fail_limit) const;
result_list test_one(path_type const & style_path,
config cfg, report_type & report,
report_type & report,
std::atomic<std::size_t> & fail_limit) const;
void parse_map_sizes(std::string const & str, std::vector<map_size> & sizes) const;
const map_sizes_grammar<std::string::const_iterator> map_sizes_parser_;
const path_type styles_dir_;
const path_type output_dir_;
const path_type reference_dir_;
const config defaults_;
const std::size_t jobs_;
const std::size_t iterations_;
const std::size_t fail_limit_;
const renderer_type renderers_[boost::mpl::size<renderer_type::types>::value];
const renderer_container renderers_;
};
}