diff --git a/.gitignore b/.gitignore index eb3ccbd1a..fcf40c453 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.os *.so *.a +*.swp *.dylib plugins/input/*.input plugins/input/templates/*.input diff --git a/benchmark/compare_images.hpp b/benchmark/compare_images.hpp index 60f9f0d1c..0f0c0f14d 100644 --- a/benchmark/compare_images.hpp +++ b/benchmark/compare_images.hpp @@ -1,8 +1,7 @@ #ifndef __MAPNIK_COMPARE_IMAGES_HPP__ #define __MAPNIK_COMPARE_IMAGES_HPP__ -#include -#include +#include #include #include @@ -17,19 +16,15 @@ namespace benchmark { { throw mapnik::image_reader_exception("Failed to load: " + dest_fn); } - std::shared_ptr image_ptr1 = std::make_shared(reader1->width(),reader1->height()); - reader1->read(0,0,image_ptr1->data()); std::unique_ptr reader2(mapnik::get_image_reader(src_fn,"png")); if (!reader2.get()) { throw mapnik::image_reader_exception("Failed to load: " + src_fn); } - std::shared_ptr image_ptr2 = std::make_shared(reader2->width(),reader2->height()); - reader2->read(0,0,image_ptr2->data()); - image_data_rgba8 const& dest = image_ptr1->data(); - image_data_rgba8 const& src = image_ptr2->data(); + image_rgba8 const& dest = util::get(reader1->read(0,0,reader1->width(), reader1->height())); + image_rgba8 const& src = util::get(reader1->read(0,0,reader1->width(), reader1->height())); unsigned int width = src.width(); unsigned int height = src.height(); diff --git a/benchmark/test_font_registration.cpp b/benchmark/test_font_registration.cpp index 749f12232..0fd9f8d29 100644 --- a/benchmark/test_font_registration.cpp +++ b/benchmark/test_font_registration.cpp @@ -24,4 +24,4 @@ public: } }; -BENCHMARK(test,"font registration") \ No newline at end of file +BENCHMARK(test,"font registration") diff --git a/benchmark/test_png_encoding1.cpp b/benchmark/test_png_encoding1.cpp index 9c1005ef7..55d3f18af 100644 --- a/benchmark/test_png_encoding1.cpp +++ b/benchmark/test_png_encoding1.cpp @@ -1,10 +1,9 @@ #include "bench_framework.hpp" #include -#include class test : public benchmark::test_case { - mapnik::image_data_rgba8 im_; + mapnik::image_rgba8 im_; public: test(mapnik::parameters const& params) : test_case(params), diff --git a/benchmark/test_png_encoding2.cpp b/benchmark/test_png_encoding2.cpp index da55bf29e..640050c0d 100644 --- a/benchmark/test_png_encoding2.cpp +++ b/benchmark/test_png_encoding2.cpp @@ -3,7 +3,7 @@ class test : public benchmark::test_case { - std::shared_ptr im_; + std::shared_ptr im_; public: test(mapnik::parameters const& params) : test_case(params) { @@ -13,14 +13,14 @@ public: { throw mapnik::image_reader_exception("Failed to load: " + filename); } - im_ = std::make_shared(reader->width(),reader->height()); - reader->read(0,0,im_->data()); + im_ = std::make_shared(reader->width(),reader->height()); + reader->read(0,0,*im_); } bool validate() const { std::string expected("./benchmark/data/multicolor-hextree-expected.png"); std::string actual("./benchmark/data/multicolor-hextree-actual.png"); - mapnik::save_to_file(im_->data(),actual, "png8:m=h:z=1"); + mapnik::save_to_file(*im_,actual, "png8:m=h:z=1"); return benchmark::compare_images(actual,expected); } bool operator()() const @@ -28,7 +28,7 @@ public: std::string out; for (std::size_t i=0;idata(),"png8:m=h:z=1"); + out = mapnik::save_to_string(*im_,"png8:m=h:z=1"); } } return true; diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index 9a3ec2942..c26ffa03b 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -37,12 +36,12 @@ void render(mapnik::geometry_type const& geom, using ren_base = agg::renderer_base; using renderer = agg::renderer_scanline_aa_solid; mapnik::vertex_adapter va(geom); - mapnik::image_32 im(256,256); - im.set_background(mapnik::color("white")); + mapnik::image_rgba8 im(256,256); + mapnik::fill(im, mapnik::color("white")); mapnik::box2d padded_extent = extent; padded_extent.pad(10); mapnik::view_transform tr(im.width(),im.height(),padded_extent,0,0); - agg::rendering_buffer buf(im.raw_data(),im.width(),im.height(), im.width() * 4); + agg::rendering_buffer buf(im.getBytes(),im.width(),im.height(), im.getRowSize()); agg::pixfmt_rgba32_plain pixf(buf); ren_base renb(pixf); renderer ren(renb); @@ -53,7 +52,7 @@ void render(mapnik::geometry_type const& geom, ras.add_path(path); agg::scanline_u8 sl; agg::render_scanlines(ras, sl, ren); - mapnik::save_to_file(im.data(),name); + mapnik::save_to_file(im,name); } class test1 : public benchmark::test_case diff --git a/benchmark/test_polygon_clipping_rendering.cpp b/benchmark/test_polygon_clipping_rendering.cpp index f4ba0f44b..88f20d5e0 100644 --- a/benchmark/test_polygon_clipping_rendering.cpp +++ b/benchmark/test_polygon_clipping_rendering.cpp @@ -1,7 +1,6 @@ #include "bench_framework.hpp" #include #include -#include #include #include @@ -22,8 +21,8 @@ public: mapnik::Map m(256,256); mapnik::load_map(m,xml_); m.zoom_to_box(extent_); - mapnik::image_32 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); ren.apply(); //mapnik::save_to_file(im.data(),"test.png"); return true; @@ -35,8 +34,8 @@ public: m.zoom_to_box(extent_); for (unsigned i=0;i ren(m,im); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); ren.apply(); } return true; diff --git a/benchmark/test_rendering.cpp b/benchmark/test_rendering.cpp index ffaa100df..30e80be77 100644 --- a/benchmark/test_rendering.cpp +++ b/benchmark/test_rendering.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -55,12 +54,12 @@ public: } else { m.zoom_all(); } - mapnik::image_32 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im,scale_factor_); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im,scale_factor_); ren.apply(); if (!preview_.empty()) { std::clog << "preview available at " << preview_ << "\n"; - mapnik::save_to_file(im.data(),preview_); + mapnik::save_to_file(im,preview_); } return true; } @@ -78,8 +77,8 @@ public: } for (unsigned i=0;i ren(m,im,scale_factor_); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im,scale_factor_); ren.apply(); } return true; diff --git a/benchmark/test_rendering_shared_map.cpp b/benchmark/test_rendering_shared_map.cpp index c5d5b08f8..a83410d1b 100644 --- a/benchmark/test_rendering_shared_map.cpp +++ b/benchmark/test_rendering_shared_map.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -50,7 +49,7 @@ class test : public benchmark::test_case std::shared_ptr m_; double scale_factor_; std::string preview_; - mutable mapnik::image_32 im_; + mutable mapnik::image_rgba8 im_; public: test(mapnik::parameters const& params) : test_case(params), @@ -94,14 +93,14 @@ public: mapnik::projection map_proj(m_->srs(),true); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); scale_denom *= scale_factor_; - mapnik::agg_renderer ren(*m_,m_req,variables,im_,scale_factor_); + mapnik::agg_renderer ren(*m_,m_req,variables,im_,scale_factor_); ren.start_map_processing(*m_); std::vector const& layers = m_->layers(); process_layers(ren,m_req,map_proj,layers,scale_denom); ren.end_map_processing(*m_); if (!preview_.empty()) { std::clog << "preview available at " << preview_ << "\n"; - mapnik::save_to_file(im_.data(),preview_); + mapnik::save_to_file(im_,preview_); } return true; } @@ -114,20 +113,20 @@ public: for (unsigned i=0;iwidth(),m_->height()); + mapnik::image_rgba8 im(m_->width(),m_->height()); mapnik::attributes variables; m_req.set_buffer_size(m_->buffer_size()); mapnik::projection map_proj(m_->srs(),true); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); scale_denom *= scale_factor_; - mapnik::agg_renderer ren(*m_,m_req,variables,im,scale_factor_); + mapnik::agg_renderer ren(*m_,m_req,variables,im,scale_factor_); ren.start_map_processing(*m_); std::vector const& layers = m_->layers(); process_layers(ren,m_req,map_proj,layers,scale_denom); ren.end_map_processing(*m_); bool diff = false; - mapnik::image_data_rgba8 const& dest = im.data(); - mapnik::image_data_rgba8 const& src = im_.data(); + mapnik::image_rgba8 const& dest = im; + mapnik::image_rgba8 const& src = im_; for (unsigned int y = 0; y < height_; ++y) { const unsigned int* row_from = src.getRow(y); diff --git a/bindings/python/mapnik_color.cpp b/bindings/python/mapnik_color.cpp index fc642f449..3e8df62f9 100644 --- a/bindings/python/mapnik_color.cpp +++ b/bindings/python/mapnik_color.cpp @@ -57,17 +57,39 @@ void export_color () "and an alpha value.\n" "All values between 0 and 255.\n") ) + .def(init( + ( arg("r"), arg("g"), arg("b"), arg("a"), arg("premultiplied") ), + "Creates a new color from its RGB components\n" + "and an alpha value.\n" + "All values between 0 and 255.\n") + ) .def(init( ( arg("r"), arg("g"), arg("b") ), "Creates a new color from its RGB components.\n" "All values between 0 and 255.\n") ) + .def(init( + ( arg("val") ), + "Creates a new color from an unsigned integer.\n" + "All values between 0 and 2^32-1\n") + ) + .def(init( + ( arg("val"), arg("premultiplied") ), + "Creates a new color from an unsigned integer.\n" + "All values between 0 and 2^32-1\n") + ) .def(init( ( arg("color_string") ), "Creates a new color from its CSS string representation.\n" "The string may be a CSS color name (e.g. 'blue')\n" "or a hex color string (e.g. '#0000ff').\n") ) + .def(init( + ( arg("color_string"), arg("premultiplied") ), + "Creates a new color from its CSS string representation.\n" + "The string may be a CSS color name (e.g. 'blue')\n" + "or a hex color string (e.g. '#0000ff').\n") + ) .add_property("r", &color::red, &color::set_red, @@ -92,6 +114,10 @@ void export_color () .def(self != self) .def_pickle(color_pickle_suite()) .def("__str__",&color::to_string) + .def("set_premultiplied",&color::set_premultiplied) + .def("get_premultiplied",&color::get_premultiplied) + .def("premultiply",&color::premultiply) + .def("demultiply",&color::demultiply) .def("packed",&color::rgba) .def("to_hex_string",&color::to_hex_string, "Returns the hexadecimal representation of this color.\n" diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index c6f30e905..c5f9a0b69 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -35,11 +35,13 @@ #pragma GCC diagnostic pop // mapnik -#include +#include #include #include +#include #include #include +#include // cairo #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) @@ -49,7 +51,7 @@ #include #endif -using mapnik::image_32; +using mapnik::image_any; using mapnik::image_reader; using mapnik::get_image_reader; using mapnik::type_from_filename; @@ -58,22 +60,21 @@ using mapnik::save_to_file; using namespace boost::python; // output 'raw' pixels -PyObject* tostring1( image_32 const& im) +PyObject* tostring1( image_any const& im) { - int size = im.width() * im.height() * 4; return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize #else ::PyString_FromStringAndSize #endif - ((const char*)im.raw_data(),size); + ((const char*)im.getBytes(),im.getSize()); } // encode (png,jpeg) -PyObject* tostring2(image_32 const & im, std::string const& format) +PyObject* tostring2(image_any const & im, std::string const& format) { - std::string s = mapnik::save_to_string(im.data(), format); + std::string s = mapnik::save_to_string(im, format); return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize @@ -83,9 +84,9 @@ PyObject* tostring2(image_32 const & im, std::string const& format) (s.data(),s.size()); } -PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* tostring3(image_any const & im, std::string const& format, mapnik::rgba_palette const& pal) { - std::string s = mapnik::save_to_string(im.data(), format, pal); + std::string s = mapnik::save_to_string(im, format, pal); return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize @@ -96,66 +97,144 @@ PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba } -void save_to_file1(mapnik::image_32 const& im, std::string const& filename) +void save_to_file1(mapnik::image_any const& im, std::string const& filename) { - save_to_file(im.data(),filename); + save_to_file(im,filename); } -void save_to_file2(mapnik::image_32 const& im, std::string const& filename, std::string const& type) +void save_to_file2(mapnik::image_any const& im, std::string const& filename, std::string const& type) { - save_to_file(im.data(),filename,type); + save_to_file(im,filename,type); } -void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) +void save_to_file3(mapnik::image_any const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) { - save_to_file(im.data(),filename,type,pal); + save_to_file(im,filename,type,pal); } -bool painted(mapnik::image_32 const& im) +mapnik::image_view_any get_view(mapnik::image_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) { - return im.painted(); + return mapnik::create_view(data,x,y,w,h); } -bool is_solid(mapnik::image_32 const& im) +bool is_solid(mapnik::image_any const& im) { - if (im.width() > 0 && im.height() > 0) + return mapnik::is_solid(im); +} + +void fill_color(mapnik::image_any & im, mapnik::color const& c) +{ + mapnik::fill(im, c); +} + +void fill_int(mapnik::image_any & im, int val) +{ + mapnik::fill(im, val); +} + +void fill_double(mapnik::image_any & im, double val) +{ + mapnik::fill(im, val); +} + +std::shared_ptr copy(mapnik::image_any const& im, mapnik::image_dtype type, double offset, double scaling) +{ + return std::make_shared(std::move(mapnik::image_copy(im, type, offset, scaling))); +} + +unsigned compare(mapnik::image_any const& im1, mapnik::image_any const& im2, double threshold, bool alpha) +{ + return mapnik::compare(im1, im2, threshold, alpha); +} + +struct get_pixel_visitor +{ + get_pixel_visitor(unsigned x, unsigned y) + : x_(x), y_(y) {} + + PyObject* operator() (mapnik::image_null const&) { - mapnik::image_data_rgba8 const & data = im.data(); - mapnik::image_data_rgba8::pixel_type const* first_row = data.getRow(0); - mapnik::image_data_rgba8::pixel_type const first_pixel = first_row[0]; - for (unsigned y = 0; y < im.height(); ++y) - { - mapnik::image_data_rgba8::pixel_type const * row = data.getRow(y); - for (unsigned x = 0; x < im.width(); ++x) - { - if (first_pixel != row[x]) - { - return false; - } - } - } + throw std::runtime_error("Can not return a null image from a pixel (shouldn't have reached here)"); } - return true; -} - -unsigned get_pixel(mapnik::image_32 const& im, int x, int y) -{ - if (x < static_cast(im.width()) && y < static_cast(im.height())) + + PyObject* operator() (mapnik::image_gray32f const& im) { - mapnik::image_data_rgba8 const & data = im.data(); - return data(x,y); + return PyFloat_FromDouble(mapnik::get_pixel(im, x_, y_)); + } + + PyObject* operator() (mapnik::image_gray64f const& im) + { + return PyFloat_FromDouble(mapnik::get_pixel(im, x_, y_)); + } + + template + PyObject* operator() (T const& im) + { + using pixel_type = typename T::pixel_type; + return PyInt_FromLong(mapnik::get_pixel(im, x_, y_)); + } + + private: + unsigned x_; + unsigned y_; +}; + +PyObject* get_pixel(mapnik::image_any const& im, unsigned x, unsigned y) +{ + if (x < static_cast(im.width()) && y < static_cast(im.height())) + { + return mapnik::util::apply_visitor(get_pixel_visitor(x, y), im); } PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); boost::python::throw_error_already_set(); return 0; } -void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c) +mapnik::color get_pixel_color(mapnik::image_any const& im, unsigned x, unsigned y) { - im.setPixel(x, y, c.rgba()); + if (x < static_cast(im.width()) && y < static_cast(im.height())) + { + return mapnik::get_pixel(im, x, y); + } + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return 0; } -std::shared_ptr open_from_file(std::string const& filename) +void set_pixel_color(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color const& c) +{ + if (x >= static_cast(im.width()) && y >= static_cast(im.height())) + { + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return; + } + mapnik::set_pixel(im, x, y, c); +} + +void set_pixel_double(mapnik::image_any & im, unsigned x, unsigned y, double val) +{ + if (x >= static_cast(im.width()) && y >= static_cast(im.height())) + { + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return; + } + mapnik::set_pixel(im, x, y, val); +} + +void set_pixel_int(mapnik::image_any & im, unsigned x, unsigned y, int val) +{ + if (x >= static_cast(im.width()) && y >= static_cast(im.height())) + { + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return; + } + mapnik::set_pixel(im, x, y, val); +} + +std::shared_ptr open_from_file(std::string const& filename) { boost::optional type = type_from_filename(filename); if (type) @@ -163,29 +242,24 @@ std::shared_ptr open_from_file(std::string const& filename) std::unique_ptr reader(get_image_reader(filename,*type)); if (reader.get()) { - - std::shared_ptr image_ptr = std::make_shared(reader->width(),reader->height()); - reader->read(0,0,image_ptr->data()); - return image_ptr; + return std::make_shared(std::move(reader->read(0,0,reader->width(),reader->height()))); } throw mapnik::image_reader_exception("Failed to load: " + filename); } throw mapnik::image_reader_exception("Unsupported image format:" + filename); } -std::shared_ptr fromstring(std::string const& str) +std::shared_ptr fromstring(std::string const& str) { std::unique_ptr reader(get_image_reader(str.c_str(),str.size())); if (reader.get()) { - std::shared_ptr image_ptr = std::make_shared(reader->width(),reader->height()); - reader->read(0,0,image_ptr->data()); - return image_ptr; + return std::make_shared(std::move(reader->read(0,0,reader->width(), reader->height()))); } throw mapnik::image_reader_exception("Failed to load image from buffer" ); } -std::shared_ptr frombuffer(PyObject * obj) +std::shared_ptr frombuffer(PyObject * obj) { void const* buffer=0; Py_ssize_t buffer_len; @@ -194,32 +268,74 @@ std::shared_ptr frombuffer(PyObject * obj) std::unique_ptr reader(get_image_reader(reinterpret_cast(buffer),buffer_len)); if (reader.get()) { - std::shared_ptr image_ptr = std::make_shared(reader->width(),reader->height()); - reader->read(0,0,image_ptr->data()); - return image_ptr; + return std::make_shared(reader->read(0,0,reader->width(),reader->height())); } } throw mapnik::image_reader_exception("Failed to load image from buffer" ); } - -void blend (image_32 & im, unsigned x, unsigned y, image_32 const& im2, float opacity) +void set_grayscale_to_alpha(image_any & im) { - im.set_rectangle_alpha2(im2.data(),x,y,opacity); + mapnik::set_grayscale_to_alpha(im); } -void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity) +void set_grayscale_to_alpha_c(image_any & im, mapnik::color const& c) { - mapnik::composite(dst.data(),src.data(),mode,opacity,0,0,false); + mapnik::set_grayscale_to_alpha(im, c); +} + +void set_color_to_alpha(image_any & im, mapnik::color const& c) +{ + mapnik::set_color_to_alpha(im, c); +} + +void set_alpha(image_any & im, float opacity) +{ + mapnik::set_alpha(im, opacity); +} + +bool premultiplied(image_any &im) +{ + return im.get_premultiplied(); +} + +bool premultiply(image_any & im) +{ + return mapnik::premultiply_alpha(im); +} + +bool demultiply(image_any & im) +{ + return mapnik::demultiply_alpha(im); +} + +void clear(image_any & im) +{ + mapnik::fill(im, 0); +} + +void composite(image_any & dst, image_any & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy) +{ + bool demultiply_dst = mapnik::premultiply_alpha(dst); + bool demultiply_src = mapnik::premultiply_alpha(src); + mapnik::composite(dst,src,mode,opacity,dx,dy); + if (demultiply_dst) + { + mapnik::demultiply_alpha(dst); + } + if (demultiply_src) + { + mapnik::demultiply_alpha(src); + } } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) -std::shared_ptr from_cairo(PycairoSurface* py_surface) +std::shared_ptr from_cairo(PycairoSurface* py_surface) { mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); - std::shared_ptr image_ptr = std::make_shared(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface)); - cairo_image_to_rgba8(image_ptr->data(), surface); - return image_ptr; + mapnik::image_rgba8 image = mapnik::image_rgba8(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface)); + cairo_image_to_rgba8(image, surface); + return std::make_shared(std::move(image)); } #endif @@ -266,31 +382,74 @@ void export_image() .value("divide", mapnik::divide) ; - class_ >("Image","This class represents a 32 bit RGBA image.",init()) - .def("width",&image_32::width) - .def("height",&image_32::height) - .def("view",&image_32::get_view) - .def("painted",&painted) + enum_("ImageType") + .value("rgba8", mapnik::image_dtype_rgba8) + .value("gray8", mapnik::image_dtype_gray8) + .value("gray8s", mapnik::image_dtype_gray8s) + .value("gray16", mapnik::image_dtype_gray16) + .value("gray16s", mapnik::image_dtype_gray16s) + .value("gray32", mapnik::image_dtype_gray32) + .value("gray32s", mapnik::image_dtype_gray32s) + .value("gray32f", mapnik::image_dtype_gray32f) + .value("gray64", mapnik::image_dtype_gray64) + .value("gray64s", mapnik::image_dtype_gray64s) + .value("gray64f", mapnik::image_dtype_gray64f) + ; + + class_, boost::noncopyable >("Image","This class represents a image.",init()) + .def(init()) + .def(init()) + .def(init()) + .def(init()) + .def("width",&image_any::width) + .def("height",&image_any::height) + .def("view",&get_view) + .def("painted",&image_any::painted) .def("is_solid",&is_solid) - .add_property("background",make_function - (&image_32::get_background,return_value_policy()), - &image_32::set_background, "The background color of the image.") - .def("set_grayscale_to_alpha",&image_32::set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image") - .def("set_color_to_alpha",&image_32::set_color_to_alpha, "Set a given color to the alpha channel of the Image") - .def("set_alpha",&image_32::set_alpha, "Set the overall alpha channel of the Image") - .def("blend",&blend) + .def("fill",&fill_color) + .def("fill",&fill_int) + .def("fill",&fill_double) + .def("set_grayscale_to_alpha",&set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image") + .def("set_grayscale_to_alpha",&set_grayscale_to_alpha_c, "Set the grayscale values to the alpha channel of the Image") + .def("set_color_to_alpha",&set_color_to_alpha, "Set a given color to the alpha channel of the Image") + .def("set_alpha",&set_alpha, "Set the overall alpha channel of the Image") .def("composite",&composite, ( arg("self"), arg("image"), arg("mode")=mapnik::src_over, - arg("opacity")=1.0f + arg("opacity")=1.0f, + arg("dx")=0, + arg("dy")=0 )) - .def("premultiplied",&image_32::premultiplied) - .def("premultiply",&image_32::premultiply) - .def("demultiply",&image_32::demultiply) - .def("set_pixel",&set_pixel) + .def("compare",&compare, + ( arg("self"), + arg("image"), + arg("threshold")=0.0, + arg("alpha")=true + )) + .def("copy",©, + ( arg("self"), + arg("type"), + arg("offset")=0.0, + arg("scaling")=1.0 + )) + .add_property("offset", + &image_any::get_offset, + &image_any::set_offset, + "Gets or sets the offset component.\n") + .add_property("scaling", + &image_any::get_scaling, + &image_any::set_scaling, + "Gets or sets the offset component.\n") + .def("premultiplied",&premultiplied) + .def("premultiply",&premultiply) + .def("demultiply",&demultiply) + .def("set_pixel",&set_pixel_color) + .def("set_pixel",&set_pixel_double) + .def("set_pixel",&set_pixel_int) .def("get_pixel",&get_pixel) - .def("clear",&image_32::clear) + .def("get_pixel_color",&get_pixel_color) + .def("clear",&clear) //TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3 .def("tostring",&tostring1) diff --git a/bindings/python/mapnik_image_view.cpp b/bindings/python/mapnik_image_view.cpp index e08129f7f..1c48bd33b 100644 --- a/bindings/python/mapnik_image_view.cpp +++ b/bindings/python/mapnik_image_view.cpp @@ -35,26 +35,21 @@ #pragma GCC diagnostic pop // mapnik -#include +#include #include +#include #include #include -#include #include -using mapnik::image_data_rgba8; -using mapnik::image_view; +using mapnik::image_view_any; using mapnik::save_to_file; // output 'raw' pixels -PyObject* view_tostring1(image_view const& view) +PyObject* view_tostring1(image_view_any const& view) { std::ostringstream ss(std::ios::out|std::ios::binary); - for (unsigned i=0;i(view.getRow(i)), - view.width() * sizeof(image_view::pixel_type)); - } + mapnik::view_to_string(view, ss); return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize @@ -65,7 +60,7 @@ PyObject* view_tostring1(image_view const& view) } // encode (png,jpeg) -PyObject* view_tostring2(image_view const & view, std::string const& format) +PyObject* view_tostring2(image_view_any const & view, std::string const& format) { std::string s = save_to_string(view, format); return @@ -77,7 +72,7 @@ PyObject* view_tostring2(image_view const & view, std::string (s.data(),s.size()); } -PyObject* view_tostring3(image_view const & view, std::string const& format, mapnik::rgba_palette const& pal) +PyObject* view_tostring3(image_view_any const & view, std::string const& format, mapnik::rgba_palette const& pal) { std::string s = save_to_string(view, format, pal); return @@ -89,41 +84,25 @@ PyObject* view_tostring3(image_view const & view, std::string (s.data(),s.size()); } -bool is_solid(image_view const& view) +bool is_solid(image_view_any const& view) { - if (view.width() > 0 && view.height() > 0) - { - mapnik::image_view::pixel_type const* first_row = view.getRow(0); - mapnik::image_view::pixel_type const first_pixel = first_row[0]; - for (unsigned y = 0; y < view.height(); ++y) - { - mapnik::image_view::pixel_type const * row = view.getRow(y); - for (unsigned x = 0; x < view.width(); ++x) - { - if (first_pixel != row[x]) - { - return false; - } - } - } - } - return true; + return mapnik::is_solid(view); } -void save_view1(image_view const& view, +void save_view1(image_view_any const& view, std::string const& filename) { save_to_file(view,filename); } -void save_view2(image_view const& view, +void save_view2(image_view_any const& view, std::string const& filename, std::string const& type) { save_to_file(view,filename,type); } -void save_view3(image_view const& view, +void save_view3(image_view_any const& view, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal) @@ -135,9 +114,9 @@ void save_view3(image_view const& view, void export_image_view() { using namespace boost::python; - class_ >("ImageView","A view into an image.",no_init) - .def("width",&image_view::width) - .def("height",&image_view::height) + class_("ImageView","A view into an image.",no_init) + .def("width",&image_view_any::width) + .def("height",&image_view_any::height) .def("is_solid",&is_solid) .def("tostring",&view_tostring1) .def("tostring",&view_tostring2) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 73fba74f6..a65120a43 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -99,9 +99,9 @@ void export_logger(); #include #include #include -#include #include #include +#include #include #include #include @@ -136,12 +136,16 @@ void clear_cache() #endif } -#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) +#if defined(HAVE_CAIRO) +#include #include +#include +#endif + +#if defined(HAVE_PYCAIRO) #include #include #include -#include static Pycairo_CAPI_t *Pycairo_CAPI; static void *extract_surface(PyObject* op) { @@ -188,19 +192,129 @@ bool python_thread::thread_support = true; #endif boost::thread_specific_ptr python_thread::state; +struct agg_renderer_visitor_1 +{ + agg_renderer_visitor_1(mapnik::Map const& m, double scale_factor, unsigned offset_x, unsigned offset_y) + : m_(m), scale_factor_(scale_factor), offset_x_(offset_x), offset_y_(offset_y) {} + + template + void operator() (T & pixmap) + { + throw std::runtime_error("This image type is not currently supported for rendering."); + } + + private: + mapnik::Map const& m_; + double scale_factor_; + unsigned offset_x_; + unsigned offset_y_; +}; + +template <> +void agg_renderer_visitor_1::operator() (mapnik::image_rgba8 & pixmap) +{ + mapnik::agg_renderer ren(m_,pixmap,scale_factor_,offset_x_, offset_y_); + ren.apply(); +} + +struct agg_renderer_visitor_2 +{ + agg_renderer_visitor_2(mapnik::Map const &m, std::shared_ptr detector, + double scale_factor, unsigned offset_x, unsigned offset_y) + : m_(m), detector_(detector), scale_factor_(scale_factor), offset_x_(offset_x), offset_y_(offset_y) {} + + template + void operator() (T & pixmap) + { + throw std::runtime_error("This image type is not currently supported for rendering."); + } + + private: + mapnik::Map const& m_; + std::shared_ptr detector_; + double scale_factor_; + unsigned offset_x_; + unsigned offset_y_; +}; + +template <> +void agg_renderer_visitor_2::operator() (mapnik::image_rgba8 & pixmap) +{ + mapnik::agg_renderer ren(m_,pixmap,detector_, scale_factor_,offset_x_, offset_y_); + ren.apply(); +} + +struct agg_renderer_visitor_3 +{ + agg_renderer_visitor_3(mapnik::Map const& m, mapnik::request const& req, mapnik::attributes const& vars, + double scale_factor, unsigned offset_x, unsigned offset_y) + : m_(m), req_(req), vars_(vars), scale_factor_(scale_factor), offset_x_(offset_x), offset_y_(offset_y) {} + + template + void operator() (T & pixmap) + { + throw std::runtime_error("This image type is not currently supported for rendering."); + } + + private: + mapnik::Map const& m_; + mapnik::request const& req_; + mapnik::attributes const& vars_; + double scale_factor_; + unsigned offset_x_; + unsigned offset_y_; + +}; + +template <> +void agg_renderer_visitor_3::operator() (mapnik::image_rgba8 & pixmap) +{ + mapnik::agg_renderer ren(m_,req_, vars_, pixmap, scale_factor_, offset_x_, offset_y_); + ren.apply(); +} + +struct agg_renderer_visitor_4 +{ + agg_renderer_visitor_4(mapnik::Map const& m, double scale_factor, unsigned offset_x, unsigned offset_y, + mapnik::layer const& layer, std::set& names) + : m_(m), scale_factor_(scale_factor), offset_x_(offset_x), offset_y_(offset_y), + layer_(layer), names_(names) {} + + template + void operator() (T & pixmap) + { + throw std::runtime_error("This image type is not currently supported for rendering."); + } + + private: + mapnik::Map const& m_; + double scale_factor_; + unsigned offset_x_; + unsigned offset_y_; + mapnik::layer const& layer_; + std::set & names_; +}; + +template <> +void agg_renderer_visitor_4::operator() (mapnik::image_rgba8 & pixmap) +{ + mapnik::agg_renderer ren(m_,pixmap,scale_factor_,offset_x_, offset_y_); + ren.apply(layer_, names_); +} + + void render(mapnik::Map const& map, - mapnik::image_32& image, + mapnik::image_any& image, double scale_factor = 1.0, unsigned offset_x = 0u, unsigned offset_y = 0u) { python_unblock_auto_block b; - mapnik::agg_renderer ren(map,image,scale_factor,offset_x, offset_y); - ren.apply(); + mapnik::util::apply_visitor(agg_renderer_visitor_1(map, scale_factor, offset_x, offset_y), image); } void render_with_vars(mapnik::Map const& map, - mapnik::image_32& image, + mapnik::image_any& image, boost::python::dict const& d, double scale_factor = 1.0, unsigned offset_x = 0u, @@ -210,25 +324,23 @@ void render_with_vars(mapnik::Map const& map, mapnik::request req(map.width(),map.height(),map.get_current_extent()); req.set_buffer_size(map.buffer_size()); python_unblock_auto_block b; - mapnik::agg_renderer ren(map,req,vars,image,scale_factor,offset_x,offset_y); - ren.apply(); + mapnik::util::apply_visitor(agg_renderer_visitor_3(map, req, vars, scale_factor, offset_x, offset_y), image); } void render_with_detector( mapnik::Map const& map, - mapnik::image_32 &image, + mapnik::image_any &image, std::shared_ptr detector, double scale_factor = 1.0, unsigned offset_x = 0u, unsigned offset_y = 0u) { python_unblock_auto_block b; - mapnik::agg_renderer ren(map,image,detector,scale_factor,offset_x,offset_y); - ren.apply(); + mapnik::util::apply_visitor(agg_renderer_visitor_2(map, detector, scale_factor, offset_x, offset_y), image); } void render_layer2(mapnik::Map const& map, - mapnik::image_32& image, + mapnik::image_any& image, unsigned layer_idx, double scale_factor, unsigned offset_x, @@ -245,9 +357,8 @@ void render_layer2(mapnik::Map const& map, python_unblock_auto_block b; mapnik::layer const& layer = layers[layer_idx]; - mapnik::agg_renderer ren(map,image,scale_factor,offset_x,offset_y); std::set names; - ren.apply(layer,names); + mapnik::util::apply_visitor(agg_renderer_visitor_4(map, scale_factor, offset_x, offset_y, layer, names), image); } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) @@ -350,9 +461,9 @@ void render_tile_to_file(mapnik::Map const& map, std::string const& file, std::string const& format) { - mapnik::image_32 image(width,height); + mapnik::image_any image(width,height); render(map,image,1.0,offset_x, offset_y); - mapnik::save_to_file(image.data(),file,format); + mapnik::save_to_file(image,file,format); } void render_to_file1(mapnik::Map const& map, @@ -385,9 +496,9 @@ void render_to_file1(mapnik::Map const& map, } else { - mapnik::image_32 image(map.width(),map.height()); + mapnik::image_any image(map.width(),map.height()); render(map,image,1.0,0,0); - mapnik::save_to_file(image.data(),filename,format); + mapnik::save_to_file(image,filename,format); } } @@ -404,9 +515,9 @@ void render_to_file2(mapnik::Map const& map,std::string const& filename) } else { - mapnik::image_32 image(map.width(),map.height()); + mapnik::image_any image(map.width(),map.height()); render(map,image,1.0,0,0); - mapnik::save_to_file(image.data(),filename); + mapnik::save_to_file(image,filename); } } @@ -442,9 +553,9 @@ void render_to_file3(mapnik::Map const& map, } else { - mapnik::image_32 image(map.width(),map.height()); + mapnik::image_any image(map.width(),map.height()); render(map,image,scale_factor,0,0); - mapnik::save_to_file(image.data(),filename,format); + mapnik::save_to_file(image,filename,format); } } @@ -724,7 +835,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("render", &render, render_overloads( "\n" - "Render Map to an AGG image_32 using offsets\n" + "Render Map to an AGG image_any using offsets\n" "\n" "Usage:\n" ">>> from mapnik import Map, Image, render, load_map\n" @@ -741,7 +852,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("render_with_detector", &render_with_detector, render_with_detector_overloads( "\n" - "Render Map to an AGG image_32 using a pre-constructed detector.\n" + "Render Map to an AGG image_any using a pre-constructed detector.\n" "\n" "Usage:\n" ">>> from mapnik import Map, Image, LabelCollisionDetector, render_with_detector, load_map\n" diff --git a/bindings/python/mapnik_symbolizer.cpp b/bindings/python/mapnik_symbolizer.cpp index ef23bdb98..2f4929229 100644 --- a/bindings/python/mapnik_symbolizer.cpp +++ b/bindings/python/mapnik_symbolizer.cpp @@ -43,7 +43,6 @@ #include #include "mapnik_enumeration.hpp" #include "mapnik_svg.hpp" -#include #include #include #include // for known_svg_prefix_ diff --git a/demo/c++/rundemo.cpp b/demo/c++/rundemo.cpp index bb354fdeb..39614bfe9 100644 --- a/demo/c++/rundemo.cpp +++ b/demo/c++/rundemo.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -37,6 +36,7 @@ #include #include #include +#include #if defined(HAVE_CAIRO) #include @@ -305,26 +305,26 @@ int main ( int, char** ) m.zoom_to_box(box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855)); - image_32 buf(m.width(),m.height()); - agg_renderer ren(m,buf); + image_rgba8 buf(m.width(),m.height()); + agg_renderer ren(m,buf); ren.apply(); std::string msg("These maps have been rendered using AGG in the current directory:\n"); #ifdef HAVE_JPEG - save_to_file(buf.data(),"demo.jpg","jpeg"); + save_to_file(buf,"demo.jpg","jpeg"); msg += "- demo.jpg\n"; #endif #ifdef HAVE_PNG - save_to_file(buf.data(),"demo.png","png"); - save_to_file(buf.data(),"demo256.png","png8"); + save_to_file(buf,"demo.png","png"); + save_to_file(buf,"demo256.png","png8"); msg += "- demo.png\n"; msg += "- demo256.png\n"; #endif #ifdef HAVE_TIFF - save_to_file(buf.data(),"demo.tif","tiff"); + save_to_file(buf,"demo.tif","tiff"); msg += "- demo.tif\n"; #endif #ifdef HAVE_WEBP - save_to_file(buf.data(),"demo.webp","webp"); + save_to_file(buf,"demo.webp","webp"); msg += "- demo.webp\n"; #endif msg += "Have a look!\n"; @@ -353,7 +353,7 @@ int main ( int, char** ) cairo_surface_write_to_png(&*image_surface, "cairo-demo.png"); // but we can also benefit from quantization by converting // to a mapnik image object and then saving that - mapnik::image_data_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); + mapnik::image_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); cairo_image_to_rgba8(im_data, image_surface); save_to_file(im_data, "cairo-demo256.png","png8"); cairo_surface_finish(&*image_surface); diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 227355d7b..8b1d6bf21 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -42,7 +41,7 @@ #include "mapwidget.hpp" #include "info_dialog.hpp" -using mapnik::image_32; +using mapnik::image_rgba8; using mapnik::Map; using mapnik::layer; using mapnik::box2d; @@ -480,7 +479,7 @@ void MapWidget::zoomToLevel(int level) void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::string const&) { - //image_32 image(width,height); + //image_rgba8 image(width,height); //agg_renderer renderer(map,image); //renderer.apply(); //image.saveToFile(filename,type); @@ -497,8 +496,8 @@ void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix) unsigned width=map.width(); unsigned height=map.height(); - image_32 buf(width,height); - mapnik::agg_renderer ren(map,buf,scaling_factor); + image_rgba8 buf(width,height); + mapnik::agg_renderer ren(map,buf,scaling_factor); try { @@ -541,10 +540,9 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix) mapnik::cairo_renderer renderer(map, cairo, scaling_factor); renderer.apply(); } - mapnik::image_data_rgba8 data(map.width(), map.height()); + mapnik::image_rgba8 data(map.width(), map.height()); mapnik::cairo_image_to_rgba8(data, image_surface); - image_32 buf(std::move(data)); - QImage image((uchar*)buf.raw_data(),buf.width(),buf.height(),QImage::Format_ARGB32); + QImage image((uchar*)data.getBytes(),data.width(),data.height(),QImage::Format_ARGB32); pix = QPixmap::fromImage(image.rgbSwapped()); #endif } diff --git a/demo/viewer/styles_model.cpp b/demo/viewer/styles_model.cpp index d8afc2631..e2f414e8a 100644 --- a/demo/viewer/styles_model.cpp +++ b/demo/viewer/styles_model.cpp @@ -201,7 +201,7 @@ struct symbolizer_icon { // FIXME! /* - std::shared_ptr symbol = sym.get_image(); + std::shared_ptr symbol = sym.get_image(); if (symbol) { QImage image(symbol->getBytes(), diff --git a/include/mapnik/agg_pattern_source.hpp b/include/mapnik/agg_pattern_source.hpp index 324dee630..1c5673950 100644 --- a/include/mapnik/agg_pattern_source.hpp +++ b/include/mapnik/agg_pattern_source.hpp @@ -24,7 +24,7 @@ #define MAPNIK_AGG_PATTERN_SOURCE_HPP // mapnik -#include +#include #include // agg @@ -36,7 +36,7 @@ namespace mapnik class pattern_source : private util::noncopyable { public: - pattern_source(image_data_rgba8 const& pattern, double opacity = 1.0) + pattern_source(image_rgba8 const& pattern, double opacity = 1.0) : pattern_(pattern), opacity_(opacity) {} @@ -57,7 +57,7 @@ public: static_cast(((c >> 24) & 0xff) * opacity_)); } private: - image_data_rgba8 const& pattern_; + image_rgba8 const& pattern_; double opacity_; }; } diff --git a/include/mapnik/agg_render_marker.hpp b/include/mapnik/agg_render_marker.hpp index dcd7dac9c..188b7de1e 100644 --- a/include/mapnik/agg_render_marker.hpp +++ b/include/mapnik/agg_render_marker.hpp @@ -66,7 +66,7 @@ void render_vector_marker(SvgRenderer & svg_renderer, RasterizerType & ras, Rend } template -void render_raster_marker(RendererType renb, RasterizerType & ras, image_data_rgba8 const& src, +void render_raster_marker(RendererType renb, RasterizerType & ras, image_rgba8 const& src, agg::trans_affine const& tr, double opacity, float scale_factor, bool snap_to_pixels) { @@ -81,7 +81,7 @@ void render_raster_marker(RendererType renb, RasterizerType & ras, image_data_rg && (std::fabs(0.0 - tr.shx) < agg::affine_epsilon) && (std::fabs(1.0 - tr.sy) < agg::affine_epsilon)) { - agg::rendering_buffer src_buffer((unsigned char *)src.getBytes(),src.width(),src.height(),src.width() * 4); + agg::rendering_buffer src_buffer((unsigned char *)src.getBytes(),src.width(),src.height(),src.getRowSize()); pixfmt_pre pixf_mask(src_buffer); if (snap_to_pixels) { @@ -125,7 +125,7 @@ void render_raster_marker(RendererType renb, RasterizerType & ras, image_data_rg agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), src.width(), src.height(), - src.width()*4); + src.getRowSize()); pixfmt_pre pixf(marker_buf); img_accessor_type ia(pixf); agg::trans_affine final_tr(p, 0, 0, width, height); diff --git a/include/mapnik/agg_renderer.hpp b/include/mapnik/agg_renderer.hpp index 7e50aea86..90ca07e06 100644 --- a/include/mapnik/agg_renderer.hpp +++ b/include/mapnik/agg_renderer.hpp @@ -36,7 +36,8 @@ #include #include #include -#include +#include +#include // stl #include @@ -50,10 +51,9 @@ namespace mapnik { class feature_type_style; class label_collision_detector4; class layer; - class marker; + struct marker; class proj_transform; struct rasterizer; - class image_32; } namespace mapnik { @@ -171,7 +171,7 @@ private: void setup(Map const& m); }; -extern template class MAPNIK_DECL agg_renderer; +extern template class MAPNIK_DECL agg_renderer; } // namespace mapnik diff --git a/include/mapnik/cairo/cairo_context.hpp b/include/mapnik/cairo/cairo_context.hpp index 022d04092..555d5c187 100644 --- a/include/mapnik/cairo/cairo_context.hpp +++ b/include/mapnik/cairo/cairo_context.hpp @@ -27,7 +27,8 @@ // mapnik #include #include -#include +#include +#include #include #include #include @@ -121,7 +122,7 @@ private: class cairo_pattern : private util::noncopyable { public: - explicit cairo_pattern(image_data_rgba8 const& data, double opacity = 1.0) + explicit cairo_pattern(image_rgba8 const& data, double opacity = 1.0) { int pixels = data.width() * data.height(); const unsigned int *in_ptr = data.getData(); @@ -279,7 +280,6 @@ inline cairo_ptr create_context(cairo_surface_ptr const& surface) class cairo_context : private util::noncopyable { public: - cairo_context(cairo_ptr const& cairo); inline ErrorStatus get_status() const @@ -308,8 +308,8 @@ public: void paint(); void set_pattern(cairo_pattern const& pattern); void set_gradient(cairo_gradient const& pattern, box2d const& bbox); - void add_image(double x, double y, image_data_rgba8 & data, double opacity = 1.0); - void add_image(agg::trans_affine const& tr, image_data_rgba8 & data, double opacity = 1.0); + void add_image(double x, double y, image_rgba8 const& data, double opacity = 1.0); + void add_image(agg::trans_affine const& tr, image_rgba8 const& data, double opacity = 1.0); void set_font_face(cairo_face_manager & manager, face_ptr face); void set_font_matrix(cairo_matrix_t const& matrix); void set_matrix(cairo_matrix_t const& matrix); diff --git a/include/mapnik/cairo/cairo_image_util.hpp b/include/mapnik/cairo/cairo_image_util.hpp index 5fe764bcf..f4a5a3dcd 100644 --- a/include/mapnik/cairo/cairo_image_util.hpp +++ b/include/mapnik/cairo/cairo_image_util.hpp @@ -25,7 +25,7 @@ #define MAPNIK_CAIRO_IMAGE_UTIL_HPP // mapnik -#include +#include #include // for cairo_surface_ptr // stl @@ -33,7 +33,7 @@ namespace mapnik { -static inline void cairo_image_to_rgba8(mapnik::image_data_rgba8 & data, +static inline void cairo_image_to_rgba8(mapnik::image_rgba8 & data, cairo_surface_ptr const& surface) { if (cairo_image_surface_get_format(&*surface) != CAIRO_FORMAT_ARGB32) diff --git a/include/mapnik/cairo/cairo_renderer.hpp b/include/mapnik/cairo/cairo_renderer.hpp index 5aedba82f..0914d626a 100644 --- a/include/mapnik/cairo/cairo_renderer.hpp +++ b/include/mapnik/cairo/cairo_renderer.hpp @@ -47,7 +47,7 @@ class feature_impl; class feature_type_style; class label_collision_detector4; class layer; -class marker; +struct marker; class proj_transform; class request; struct pixel_position; @@ -165,7 +165,7 @@ public: { return common_.vars_; } - + void render_marker(pixel_position const& pos, marker const& marker, agg::trans_affine const& mtx, diff --git a/include/mapnik/cairo_io.hpp b/include/mapnik/cairo_io.hpp new file mode 100644 index 000000000..c808b9970 --- /dev/null +++ b/include/mapnik/cairo_io.hpp @@ -0,0 +1,49 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_CAIRO_IO_HPP +#define MAPNIK_CAIRO_IO_HPP + +// mapnik +#include +#include + +// stl +#include + +namespace mapnik { + +#if defined(HAVE_CAIRO) +MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, + std::string const& filename, + double scale_factor=1.0, + double scale_denominator=0.0); +MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, + std::string const& filename, + std::string const& type, + double scale_factor=1.0, + double scale_denominator=0.0); +#endif + +} // end ns + +#endif // MAPNIK_CAIRO_IO_HPP diff --git a/include/mapnik/color.hpp b/include/mapnik/color.hpp index f220ddd07..e7e9ab92d 100644 --- a/include/mapnik/color.hpp +++ b/include/mapnik/color.hpp @@ -44,29 +44,39 @@ private: std::uint8_t green_; std::uint8_t blue_; std::uint8_t alpha_; - + bool premultiplied_; public: // default ctor color() : red_(0xff), green_(0xff), blue_(0xff), - alpha_(0xff) + alpha_(0xff), + premultiplied_(false) {} - color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha = 0xff) + color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha = 0xff, bool premultiplied = false) : red_(red), green_(green), blue_(blue), - alpha_(alpha) + alpha_(alpha), + premultiplied_(premultiplied) {} + color(std::uint32_t rgba, bool premultiplied = false) + : red_(rgba & 0xff), + green_((rgba >> 8) & 0xff), + blue_((rgba >> 16) & 0xff), + alpha_((rgba >> 24) & 0xff), + premultiplied_(premultiplied) {} + // copy ctor color(const color& rhs) : red_(rhs.red_), green_(rhs.green_), blue_(rhs.blue_), - alpha_(rhs.alpha_) + alpha_(rhs.alpha_), + premultiplied_(rhs.premultiplied_) {} // move ctor @@ -74,14 +84,15 @@ public: : red_(std::move(rhs.red_)), green_(std::move(rhs.green_)), blue_(std::move(rhs.blue_)), - alpha_(std::move(rhs.alpha_)) {} + alpha_(std::move(rhs.alpha_)), + premultiplied_(std::move(rhs.premultiplied_)) {} - color( std::string const& str); + color( std::string const& str, bool premultiplied = false); std::string to_string() const; std::string to_hex_string() const; - void premultiply(); - void demultiply(); + bool premultiply(); + bool demultiply(); color& operator=(color rhs) { @@ -135,6 +146,14 @@ public: { alpha_ = alpha; } + inline bool get_premultiplied() const + { + return premultiplied_; + } + inline void set_premultiplied(bool status) + { + premultiplied_ = status; + } inline unsigned rgba() const { diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp deleted file mode 100644 index 98e800107..000000000 --- a/include/mapnik/graphics.hpp +++ /dev/null @@ -1,304 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2014 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_GRAPHICS_HPP -#define MAPNIK_GRAPHICS_HPP - -// mapnik -#include -#include -#include -#include -#include -#include - -// stl -#include -#include -#include - -// boost -#include - -namespace mapnik -{ - -class MAPNIK_DECL image_32 -{ -private: - image_data_rgba8 data_; - boost::optional background_; - bool painted_; - bool premultiplied_; -public: - image_32(int width,int height); - image_32(image_32 const& rhs); - image_32(image_data_rgba8 && data); - ~image_32(); - - void painted(bool painted) - { - painted_ = painted; - } - - bool painted() const - { - return painted_; - } - - bool premultiplied() const - { - return premultiplied_; - } - - inline void clear() - { - std::fill(data_.getData(), data_.getData() + data_.width() * data_.height(), 0); - } - - boost::optional const& get_background() const; - - void set_background(const color& c); - - void premultiply(); - - void demultiply(); - - void set_grayscale_to_alpha(); - - void set_color_to_alpha(color const& c); - - void set_alpha(float opacity); - - inline const image_data_rgba8& data() const - { - return data_; - } - - inline image_data_rgba8& data() - { - return data_; - } - - inline const unsigned char* raw_data() const - { - return data_.getBytes(); - } - - inline unsigned char* raw_data() - { - return data_.getBytes(); - } - - inline image_view get_view(unsigned x,unsigned y, unsigned w,unsigned h) - { - return image_view(x,y,w,h,data_); - } - -private: - - inline bool checkBounds(int x, int y) const - { - return (x >= 0 && x < static_cast(data_.width()) && y >= 0 && y < static_cast(data_.height())); - } - -public: - inline void setPixel(int x,int y,unsigned int rgba) - { - if (checkBounds(x,y)) - { - data_(x,y)=rgba; - } - } - - void composite_pixel(unsigned op, int x,int y,unsigned c, unsigned cover, double opacity); - - inline unsigned width() const - { - return data_.width(); - } - - inline unsigned height() const - { - return data_.height(); - } - - inline void set_rectangle(int x0,int y0,image_data_rgba8 const& data) - { - box2d ext0(0,0,data_.width(),data_.height()); - box2d ext1(x0,y0,x0+data.width(),y0+data.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (int y = box.miny(); y < box.maxy(); ++y) - { - unsigned int* row_to = data_.getRow(y); - unsigned int const * row_from = data.getRow(y-y0); - - for (int x = box.minx(); x < box.maxx(); ++x) - { - if (row_from[x-x0] & 0xff000000) - { - row_to[x] = row_from[x-x0]; - } - } - } - } - } - - inline void set_rectangle_alpha(int x0,int y0,const image_data_rgba8& data) - { - box2d ext0(0,0,data_.width(),data_.height()); - box2d ext1(x0,y0,x0 + data.width(),y0 + data.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (int y = box.miny(); y < box.maxy(); ++y) - { - unsigned int* row_to = data_.getRow(y); - unsigned int const * row_from = data.getRow(y-y0); - for (int x = box.minx(); x < box.maxx(); ++x) - { - unsigned rgba0 = row_to[x]; - unsigned rgba1 = row_from[x-x0]; - unsigned a1 = (rgba1 >> 24) & 0xff; - if (a1 == 0) continue; - if (a1 == 0xff) - { - row_to[x] = rgba1; - continue; - } - unsigned r1 = rgba1 & 0xff; - unsigned g1 = (rgba1 >> 8 ) & 0xff; - unsigned b1 = (rgba1 >> 16) & 0xff; - - unsigned a0 = (rgba0 >> 24) & 0xff; - unsigned r0 = (rgba0 & 0xff) * a0; - unsigned g0 = ((rgba0 >> 8 ) & 0xff) * a0; - unsigned b0 = ((rgba0 >> 16) & 0xff) * a0; - - a0 = ((a1 + a0) << 8) - a0*a1; - - r0 = ((((r1 << 8) - r0) * a1 + (r0 << 8)) / a0); - g0 = ((((g1 << 8) - g0) * a1 + (g0 << 8)) / a0); - b0 = ((((b1 << 8) - b0) * a1 + (b0 << 8)) / a0); - a0 = a0 >> 8; - row_to[x] = (a0 << 24)| (b0 << 16) | (g0 << 8) | (r0) ; - } - } - } - } - - inline void set_rectangle_alpha2(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity) - { - box2d ext0(0,0,data_.width(),data_.height()); - box2d ext1(x0,y0,x0 + data.width(),y0 + data.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (int y = box.miny(); y < box.maxy(); ++y) - { - unsigned int* row_to = data_.getRow(y); - unsigned int const * row_from = data.getRow(y-y0); - for (int x = box.minx(); x < box.maxx(); ++x) - { - unsigned rgba0 = row_to[x]; - unsigned rgba1 = row_from[x-x0]; - unsigned a1 = int( ((rgba1 >> 24) & 0xff) * opacity ); - if (a1 == 0) continue; - if (a1 == 0xff) - { - row_to[x] = rgba1; - continue; - } - unsigned r1 = rgba1 & 0xff; - unsigned g1 = (rgba1 >> 8 ) & 0xff; - unsigned b1 = (rgba1 >> 16) & 0xff; - - unsigned a0 = (rgba0 >> 24) & 0xff; - unsigned r0 = rgba0 & 0xff ; - unsigned g0 = (rgba0 >> 8 ) & 0xff; - unsigned b0 = (rgba0 >> 16) & 0xff; - - unsigned atmp = a1 + a0 - ((a1 * a0 + 255) >> 8); - if (atmp) - { - r0 = byte((r1 * a1 + (r0 * a0) - ((r0 * a0 * a1 + 255) >> 8)) / atmp); - g0 = byte((g1 * a1 + (g0 * a0) - ((g0 * a0 * a1 + 255) >> 8)) / atmp); - b0 = byte((b1 * a1 + (b0 * a0) - ((b0 * a0 * a1 + 255) >> 8)) / atmp); - } - a0 = byte(atmp); - - row_to[x] = (a0 << 24)| (b0 << 16) | (g0 << 8) | (r0) ; - } - } - } - } - - template - inline void merge_rectangle(image_data_rgba8 const& data, unsigned x0, unsigned y0, float opacity) - { - box2d ext0(0,0,data_.width(),data_.height()); - box2d ext1(x0,y0,x0 + data.width(),y0 + data.height()); - - if (ext0.intersects(ext1)) - { - box2d box = ext0.intersect(ext1); - for (int y = box.miny(); y < box.maxy(); ++y) - { - unsigned int* row_to = data_.getRow(y); - unsigned int const * row_from = data.getRow(y-y0); - for (int x = box.minx(); x < box.maxx(); ++x) - { - unsigned rgba0 = row_to[x]; - unsigned rgba1 = row_from[x-x0]; - unsigned a1 = int( ((rgba1 >> 24) & 0xff) * opacity ); - if (a1 == 0) continue; - unsigned r1 = rgba1 & 0xff; - unsigned g1 = (rgba1 >> 8 ) & 0xff; - unsigned b1 = (rgba1 >> 16) & 0xff; - - unsigned a0 = (rgba0 >> 24) & 0xff; - unsigned r0 = rgba0 & 0xff ; - unsigned g0 = (rgba0 >> 8 ) & 0xff; - unsigned b0 = (rgba0 >> 16) & 0xff; - - unsigned a = (a1 * 255 + (255 - a1) * a0 + 127)/255; - - MergeMethod::mergeRGB(r0,g0,b0,r1,g1,b1); - - r0 = (r1*a1 + (((255 - a1) * a0 + 127)/255) * r0 + 127)/a; - g0 = (g1*a1 + (((255 - a1) * a0 + 127)/255) * g0 + 127)/a; - b0 = (b1*a1 + (((255 - a1) * a0 + 127)/255) * b0 + 127)/a; - - row_to[x] = (a << 24)| (b0 << 16) | (g0 << 8) | (r0) ; - } - } - } - } -}; -} - -#endif // MAPNIK_GRAPHICS_HPP diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index bd4cd1e5d..0cb948262 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -25,7 +25,7 @@ // mapnik #include -#include +#include #include #include #include @@ -35,7 +35,6 @@ #include // stl -#include #include #include #include @@ -49,8 +48,8 @@ template class MAPNIK_DECL hit_grid { public: - using value_type = T; - using data_type = mapnik::image_data; + using value_type = typename T::type; + using data_type = mapnik::image; using lookup_type = std::string; // mapping between pixel id and key using feature_key_type = std::map; @@ -147,12 +146,12 @@ public: return data_; } - inline T const * raw_data() const + inline value_type const * raw_data() const { return data_.getData(); } - inline T* raw_data() + inline value_type* raw_data() { return data_.getData(); } @@ -195,7 +194,7 @@ public: return height_; } - inline void set_rectangle(value_type id,image_data_rgba8 const& data,int x0,int y0) + inline void set_rectangle(value_type id,image_rgba8 const& data,int x0,int y0) { box2d ext0(0,0,width_,height_); box2d ext1(x0,y0,x0+data.width(),y0+data.height()); @@ -222,10 +221,9 @@ public: } } } - }; -using grid = hit_grid; +using grid = hit_grid; } #endif //MAPNIK_GRID_HPP diff --git a/include/mapnik/grid/grid_render_marker.hpp b/include/mapnik/grid/grid_render_marker.hpp index 454ae038f..79c5ec097 100644 --- a/include/mapnik/grid/grid_render_marker.hpp +++ b/include/mapnik/grid/grid_render_marker.hpp @@ -41,7 +41,7 @@ namespace mapnik { template void render_raster_marker(RendererType ren, RasterizerType & ras, - image_data_rgba8 & src, + image_rgba8 const& src, mapnik::feature_impl const& feature, agg::trans_affine const& marker_tr, double opacity) diff --git a/include/mapnik/grid/grid_renderer.hpp b/include/mapnik/grid/grid_renderer.hpp index 500c95059..2db770984 100644 --- a/include/mapnik/grid/grid_renderer.hpp +++ b/include/mapnik/grid/grid_renderer.hpp @@ -49,7 +49,7 @@ namespace mapnik { class feature_type_style; class label_collision_detector4; class layer; - class marker; + struct marker; class proj_transform; struct grid_rasterizer; class request; diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index e43633e97..43c50da88 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -23,7 +23,7 @@ #ifndef MAPNIK_GRID_VIEW_HPP #define MAPNIK_GRID_VIEW_HPP -#include +#include #include #include #include @@ -196,7 +196,7 @@ private: feature_type const& features_; }; -using grid_view = hit_grid_view >; +using grid_view = hit_grid_view >; } diff --git a/include/mapnik/image_data.hpp b/include/mapnik/image.hpp similarity index 69% rename from include/mapnik/image_data.hpp rename to include/mapnik/image.hpp index 833a0f16e..e9796e3db 100644 --- a/include/mapnik/image_data.hpp +++ b/include/mapnik/image.hpp @@ -25,10 +25,13 @@ // mapnik #include +#include + // stl #include #include #include +#include namespace mapnik { @@ -116,45 +119,70 @@ struct image_dimensions } template -class image_data +class image { public: - using pixel_type = T; + using pixel = T; + using pixel_type = typename T::type; static constexpr std::size_t pixel_size = sizeof(pixel_type); - - image_data(int width, int height, bool initialize = true) +private: + detail::image_dimensions dimensions_; + detail::buffer buffer_; + pixel_type *pData_; + double offset_; + double scaling_; + bool premultiplied_alpha_; + bool painted_; +public: + image(int width, int height, bool initialize = true, bool premultiplied = false, bool painted = false) : dimensions_(width, height), buffer_(dimensions_.width() * dimensions_.height() * pixel_size), - pData_(reinterpret_cast(buffer_.data())) + pData_(reinterpret_cast(buffer_.data())), + offset_(0.0), + scaling_(1.0), + premultiplied_alpha_(premultiplied), + painted_(painted) { if (pData_ && initialize) std::fill(pData_, pData_ + dimensions_.width() * dimensions_.height(), 0); } - image_data(image_data const& rhs) + image(image const& rhs) : dimensions_(rhs.dimensions_), buffer_(rhs.buffer_), - pData_(reinterpret_cast(buffer_.data())) + pData_(reinterpret_cast(buffer_.data())), + offset_(rhs.offset_), + scaling_(rhs.scaling_), + premultiplied_alpha_(rhs.premultiplied_alpha_), + painted_(rhs.painted_) {} - image_data(image_data && rhs) noexcept + image(image && rhs) noexcept : dimensions_(std::move(rhs.dimensions_)), - buffer_(std::move(rhs.buffer_)), - pData_(reinterpret_cast(buffer_.data())) + buffer_(std::move(rhs.buffer_)), + pData_(reinterpret_cast(buffer_.data())), + offset_(rhs.offset_), + scaling_(rhs.scaling_), + premultiplied_alpha_(rhs.premultiplied_alpha_), + painted_(rhs.painted_) { rhs.dimensions_ = { 0, 0 }; rhs.pData_ = nullptr; } - image_data& operator=(image_data rhs) + image& operator=(image rhs) { swap(rhs); return *this; } - void swap(image_data & rhs) + void swap(image & rhs) { std::swap(dimensions_, rhs.dimensions_); std::swap(buffer_, rhs.buffer_); + std::swap(offset_, rhs.offset_); + std::swap(scaling_, rhs.scaling_); + std::swap(premultiplied_alpha_, rhs.premultiplied_alpha_); + std::swap(painted_, rhs.painted_); } inline pixel_type& operator() (std::size_t i, std::size_t j) @@ -241,16 +269,80 @@ public: std::copy(buf, buf + (x1 - x0), pData_ + row * dimensions_.width() + x0); } -private: - detail::image_dimensions dimensions_; - detail::buffer buffer_; - pixel_type *pData_; + inline double get_offset() const + { + return offset_; + } + + inline void set_offset(double set) + { + offset_ = set; + } + + inline double get_scaling() const + { + return scaling_; + } + + inline void set_scaling(double set) + { + if (set != 0.0) + { + scaling_ = set; + return; + } + std::clog << "Can not set scaling to 0.0, offset not set." << std::endl; + } + + inline bool get_premultiplied() const + { + return premultiplied_alpha_; + } + + inline void set_premultiplied(bool set) + { + premultiplied_alpha_ = set; + } + + inline void painted(bool painted) + { + painted_ = painted; + } + + inline bool painted() const + { + return painted_; + } }; -using image_data_rgba8 = image_data; -using image_data_gray8 = image_data ; -using image_data_gray16 = image_data; -using image_data_gray32f = image_data; -} +using image_rgba8 = image; +using image_gray8 = image; +using image_gray8s = image; +using image_gray16 = image; +using image_gray16s = image; +using image_gray32 = image; +using image_gray32s = image; +using image_gray32f = image; +using image_gray64 = image; +using image_gray64s = image; +using image_gray64f = image; + +enum image_dtype : std::uint8_t +{ + image_dtype_rgba8 = 0, + image_dtype_gray8, + image_dtype_gray8s, + image_dtype_gray16, + image_dtype_gray16s, + image_dtype_gray32, + image_dtype_gray32s, + image_dtype_gray32f, + image_dtype_gray64, + image_dtype_gray64s, + image_dtype_gray64f, + image_dtype_null +}; + +} // end ns #endif // MAPNIK_IMAGE_DATA_HPP diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp new file mode 100644 index 000000000..55e75d1f2 --- /dev/null +++ b/include/mapnik/image_any.hpp @@ -0,0 +1,316 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_IMAGE_DATA_ANY_HPP +#define MAPNIK_IMAGE_DATA_ANY_HPP + +#include +#include + +namespace mapnik { + +struct image_null +{ + using pixel_type = uint8_t; + unsigned char const* getBytes() const { return nullptr; } + unsigned char* getBytes() { return nullptr;} + unsigned getSize() const { return 0; } + unsigned getRowSize() const { return 0; } + std::size_t width() const { return 0; } + std::size_t height() const { return 0; } + bool painted() const { return false; } + double get_offset() const { return 0.0; } + void set_offset(double) {} + double get_scaling() const { return 1.0; } + void set_scaling(double) {} + bool get_premultiplied() const { return false; } + void set_premultiplied(bool) {} + void set(pixel_type const&) { throw std::runtime_error("Can not set values for null image"); } + pixel_type& operator() (std::size_t, std::size_t) + { + throw std::runtime_error("Can not set or get values for null image"); + } + pixel_type const& operator() (std::size_t, std::size_t) const + { + throw std::runtime_error("Can not set or get values for null image"); + } +}; + +using image_base = util::variant; + +// Forward declaring +struct image_any; +image_any create_image_any(int width, + int height, + image_dtype type = image_dtype_rgba8, + bool initialize = true, + bool premultiplied = false, + bool painted = false); + +namespace detail { + +struct get_bytes_visitor +{ + template + unsigned char* operator()(T & data) + { + return data.getBytes(); + } +}; + +struct get_bytes_visitor_const +{ + template + unsigned char const* operator()(T const& data) const + { + return data.getBytes(); + } +}; + +struct get_width_visitor +{ + template + std::size_t operator()(T const& data) const + { + return data.width(); + } +}; + +struct get_height_visitor +{ + template + std::size_t operator()(T const& data) const + { + return data.height(); + } +}; + +struct get_premultiplied_visitor +{ + template + bool operator()(T const& data) const + { + return data.get_premultiplied(); + } +}; + +struct get_painted_visitor +{ + template + bool operator()(T const& data) const + { + return data.painted(); + } +}; + +struct get_any_size_visitor +{ + template + unsigned operator()(T const& data) const + { + return data.getSize(); + } +}; + +struct get_any_row_size_visitor +{ + template + unsigned operator()(T const& data) const + { + return data.getRowSize(); + } +}; + +struct get_offset_visitor +{ + template + double operator() (T const& data) const + { + return data.get_offset(); + } +}; + +struct get_scaling_visitor +{ + template + double operator() (T const& data) const + { + return data.get_scaling(); + } +}; + +struct set_offset_visitor +{ + set_offset_visitor(double val) + : val_(val) {} + template + void operator() (T & data) + { + data.set_offset(val_); + } + private: + double val_; +}; + +struct set_scaling_visitor +{ + set_scaling_visitor(double val) + : val_(val) {} + template + void operator() (T & data) + { + data.set_scaling(val_); + } + private: + double val_; +}; + +} // namespace detail + +struct image_any : image_base +{ + image_any() = default; + + image_any(int width, + int height, + image_dtype type = image_dtype_rgba8, + bool initialize = true, + bool premultiplied = false, + bool painted = false) + : image_base(std::move(create_image_any(width, height, type, initialize, premultiplied, painted))) {} + + template + image_any(T && data) noexcept + : image_base(std::move(data)) {} + + unsigned char const* getBytes() const + { + return util::apply_visitor(detail::get_bytes_visitor_const(),*this); + } + + unsigned char* getBytes() + { + return util::apply_visitor(detail::get_bytes_visitor(),*this); + } + + std::size_t width() const + { + return util::apply_visitor(detail::get_width_visitor(),*this); + } + + std::size_t height() const + { + return util::apply_visitor(detail::get_height_visitor(),*this); + } + + bool get_premultiplied() const + { + return util::apply_visitor(detail::get_premultiplied_visitor(),*this); + } + + bool painted() const + { + return util::apply_visitor(detail::get_painted_visitor(),*this); + } + + unsigned getSize() const + { + return util::apply_visitor(detail::get_any_size_visitor(),*this); + } + + unsigned getRowSize() const + { + return util::apply_visitor(detail::get_any_row_size_visitor(),*this); + } + + double get_offset() const + { + return util::apply_visitor(detail::get_offset_visitor(),*this); + } + + double get_scaling() const + { + return util::apply_visitor(detail::get_scaling_visitor(),*this); + } + + void set_offset(double val) + { + util::apply_visitor(detail::set_offset_visitor(val),*this); + } + + void set_scaling(double val) + { + util::apply_visitor(detail::set_scaling_visitor(val),*this); + } +}; + +inline image_any create_image_any(int width, + int height, + image_dtype type, + bool initialize, + bool premultiplied, + bool painted) +{ + switch (type) + { + case image_dtype_gray8: + return image_any(std::move(image_gray8(width, height, initialize, premultiplied, painted))); + case image_dtype_gray8s: + return image_any(std::move(image_gray8s(width, height, initialize, premultiplied, painted))); + case image_dtype_gray16: + return image_any(std::move(image_gray16(width, height, initialize, premultiplied, painted))); + case image_dtype_gray16s: + return image_any(std::move(image_gray16s(width, height, initialize, premultiplied, painted))); + case image_dtype_gray32: + return image_any(std::move(image_gray32(width, height, initialize, premultiplied, painted))); + case image_dtype_gray32s: + return image_any(std::move(image_gray32s(width, height, initialize, premultiplied, painted))); + case image_dtype_gray32f: + return image_any(std::move(image_gray32f(width, height, initialize, premultiplied, painted))); + case image_dtype_gray64: + return image_any(std::move(image_gray64(width, height, initialize, premultiplied, painted))); + case image_dtype_gray64s: + return image_any(std::move(image_gray64s(width, height, initialize, premultiplied, painted))); + case image_dtype_gray64f: + return image_any(std::move(image_gray64f(width, height, initialize, premultiplied, painted))); + case image_dtype_null: + return image_any(std::move(image_null())); + case image_dtype_rgba8: + default: + return image_any(std::move(image_rgba8(width, height, initialize, premultiplied, painted))); + } +} + +} // end mapnik ns + +#endif // MAPNIK_IMAGE_DATA_ANY_HPP diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index c72f62daa..c3fce8be7 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -24,7 +24,7 @@ #define MAPNIK_IMAGE_COMPOSITING_HPP #include -#include +#include // boost #include @@ -87,8 +87,7 @@ MAPNIK_DECL void composite(T & dst, T const& src, composite_mode_e mode, float opacity=1, int dx=0, - int dy=0, - bool premultiply_src=false); + int dy=0); } #endif // MAPNIK_IMAGE_COMPOSITING_HPP diff --git a/include/mapnik/image_copy.hpp b/include/mapnik/image_copy.hpp new file mode 100644 index 000000000..62e2ab215 --- /dev/null +++ b/include/mapnik/image_copy.hpp @@ -0,0 +1,72 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_IMAGE_COPY_HPP +#define MAPNIK_IMAGE_COPY_HPP + +#include +#include + +namespace mapnik +{ + +template +MAPNIK_DECL T image_copy(image_any const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_rgba8 const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray8 const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray8s const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray16 const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray16s const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray32 const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray32s const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray32f const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray64 const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray64s const&, double offset = 0.0, double scaling = 1.0); + +template +MAPNIK_DECL T image_copy(image_gray64f const&, double offset = 0.0, double scaling = 1.0); + +MAPNIK_DECL image_any image_copy(image_any const&, image_dtype type, double offset = 0.0, double scaling = 1.0); + +} // end mapnik ns + +#endif // MAPNIK_IMAGE_COPY_HPP diff --git a/include/mapnik/image_data_any.hpp b/include/mapnik/image_data_any.hpp deleted file mode 100644 index c09bfdf7d..000000000 --- a/include/mapnik/image_data_any.hpp +++ /dev/null @@ -1,112 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2014 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_IMAGE_DATA_ANY_HPP -#define MAPNIK_IMAGE_DATA_ANY_HPP - -#include -#include - -namespace mapnik { - -struct image_data_null -{ - unsigned char const* getBytes() const { return nullptr; } - unsigned char* getBytes() { return nullptr;} - std::size_t width() const { return 0; } - std::size_t height() const { return 0; } -}; - -using image_data_base = util::variant; - -namespace detail { - -struct get_bytes_visitor -{ - template - unsigned char* operator()(T & data) - { - return data.getBytes(); - } -}; - -struct get_bytes_visitor_const -{ - template - unsigned char const* operator()(T const& data) const - { - return data.getBytes(); - } -}; - -struct get_width_visitor -{ - template - std::size_t operator()(T const& data) const - { - return data.width(); - } -}; - -struct get_height_visitor -{ - template - std::size_t operator()(T const& data) const - { - return data.height(); - } -}; - -} // namespace detail - -struct image_data_any : image_data_base -{ - image_data_any() = default; - - template - image_data_any(T && data) noexcept - : image_data_base(std::move(data)) {} - - unsigned char const* getBytes() const - { - return util::apply_visitor(detail::get_bytes_visitor_const(),*this); - } - - unsigned char* getBytes() - { - return util::apply_visitor(detail::get_bytes_visitor(),*this); - } - - std::size_t width() const - { - return util::apply_visitor(detail::get_width_visitor(),*this); - } - - std::size_t height() const - { - return util::apply_visitor(detail::get_height_visitor(),*this); - } -}; - -} - -#endif // MAPNIK_IMAGE_DATA_ANY_HPP diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index 064e94a43..215703efb 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -139,7 +139,7 @@ boost::gil::rgba8_view_t rgba8_view(Image & img) using boost::gil::interleaved_view; using boost::gil::rgba8_pixel_t; return interleaved_view(img.width(), img.height(), - reinterpret_cast(img.raw_data()), + reinterpret_cast(img.getBytes()), img.width() * sizeof(rgba8_pixel_t)); } @@ -391,17 +391,17 @@ template void apply_filter(Src & src, Filter const& filter) { { - src.demultiply(); + demultiply_alpha(src); double_buffer tb(src); apply_convolution_3x3(tb.src_view, tb.dst_view, filter); } // ensure ~double_buffer() is called before premultiplying - src.premultiply(); + premultiply_alpha(src); } template void apply_filter(Src & src, agg_stack_blur const& op) { - agg::rendering_buffer buf(src.raw_data(),src.width(),src.height(), src.width() * 4); + agg::rendering_buffer buf(src.getBytes(),src.width(),src.height(), src.getRowSize()); agg::pixfmt_rgba32_pre pixf(buf); agg::stack_blur_rgba32(pixf,op.rx,op.ry); } diff --git a/include/mapnik/image_reader.hpp b/include/mapnik/image_reader.hpp index 31a12f4f0..471a08b58 100644 --- a/include/mapnik/image_reader.hpp +++ b/include/mapnik/image_reader.hpp @@ -24,7 +24,7 @@ #define MAPNIK_IMAGE_READER_HPP // mapnik -#include +#include #include #include #include @@ -59,10 +59,9 @@ struct MAPNIK_DECL image_reader : private util::noncopyable virtual unsigned width() const = 0; virtual unsigned height() const = 0; virtual bool has_alpha() const = 0; - virtual bool premultiplied_alpha() const = 0; virtual boost::optional > bounding_box() const = 0; - virtual void read(unsigned x,unsigned y,image_data_rgba8& image) = 0; - virtual image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) = 0; + virtual void read(unsigned x,unsigned y,image_rgba8& image) = 0; + virtual image_any read(unsigned x, unsigned y, unsigned width, unsigned height) = 0; virtual ~image_reader() {} }; diff --git a/include/mapnik/image_scaling.hpp b/include/mapnik/image_scaling.hpp index c8c916fa6..0dd94c9a6 100644 --- a/include/mapnik/image_scaling.hpp +++ b/include/mapnik/image_scaling.hpp @@ -25,7 +25,7 @@ // mapnik #include -#include +#include // stl #include diff --git a/include/mapnik/image_scaling_traits.hpp b/include/mapnik/image_scaling_traits.hpp index fe2ce61ed..9b783062c 100644 --- a/include/mapnik/image_scaling_traits.hpp +++ b/include/mapnik/image_scaling_traits.hpp @@ -38,7 +38,7 @@ template struct agg_scaling_traits {}; template <> -struct agg_scaling_traits +struct agg_scaling_traits { using pixfmt_pre = agg::pixfmt_rgba32_pre; using color_type = agg::rgba8; @@ -50,7 +50,7 @@ struct agg_scaling_traits }; template <> -struct agg_scaling_traits +struct agg_scaling_traits { using pixfmt_pre = agg::pixfmt_gray8_pre; using color_type = agg::gray8; @@ -61,7 +61,18 @@ struct agg_scaling_traits }; template <> -struct agg_scaling_traits +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray8_pre; + using color_type = agg::gray8; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits { using pixfmt_pre = agg::pixfmt_gray16_pre; using color_type = agg::gray16; @@ -72,7 +83,73 @@ struct agg_scaling_traits }; template <> -struct agg_scaling_traits +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray16_pre; + using color_type = agg::gray16; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray32_pre; + using color_type = agg::gray32; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray32_pre; + using color_type = agg::gray32; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray32_pre; + using color_type = agg::gray32; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray32_pre; + using color_type = agg::gray32; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits +{ + using pixfmt_pre = agg::pixfmt_gray32_pre; + using color_type = agg::gray32; + using interpolator_type = agg::span_interpolator_linear<>; + using img_src_type = agg::image_accessor_clone; + using span_image_filter = agg::span_image_filter_gray_nn; + using span_image_resample_affine = agg::span_image_resample_gray_affine; +}; + +template <> +struct agg_scaling_traits { using pixfmt_pre = agg::pixfmt_gray32_pre; using color_type = agg::gray32; diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index 95bc64c0d..13f30204e 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -25,8 +25,11 @@ // mapnik #include -#include +#include +#include #include +#include +#include // boost #pragma GCC diagnostic push @@ -37,13 +40,11 @@ // stl #include -#include #include namespace mapnik { // fwd declares -class Map; class rgba_palette; class ImageWriterException : public std::exception @@ -62,18 +63,6 @@ public: } }; -#if defined(HAVE_CAIRO) -MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, - std::string const& filename, - double scale_factor=1.0, - double scale_denominator=0.0); -MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, - std::string const& filename, - std::string const& type, - double scale_factor=1.0, - double scale_denominator=0.0); -#endif - template MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, @@ -121,17 +110,228 @@ MAPNIK_DECL void save_to_stream std::string const& type ); -template -void save_as_png(T const& image, - std::string const& filename, - rgba_palette const& palette); +// PREMULTIPLY ALPHA +MAPNIK_DECL bool premultiply_alpha(image_any & image); -#if defined(HAVE_JPEG) template -void save_as_jpeg(std::string const& filename, - int quality, - T const& image); -#endif +MAPNIK_DECL bool premultiply_alpha(T & image); + +// DEMULTIPLY ALPHA +MAPNIK_DECL bool demultiply_alpha(image_any & image); + +template +MAPNIK_DECL bool demultiply_alpha(T & image); + +// SET PREMULTIPLIED ALPHA +MAPNIK_DECL void set_premultiplied_alpha(image_any & image, bool status); + +template +MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status); + +// IS SOLID +MAPNIK_DECL bool is_solid (image_any const& image); +MAPNIK_DECL bool is_solid (image_view_any const& image); + +template +MAPNIK_DECL bool is_solid (T const& image); + +// SET ALPHA +MAPNIK_DECL void set_alpha (image_any & image, float opacity); + +template +MAPNIK_DECL void set_alpha (T & image, float opacity); + +// SET GRAYSCALE TO ALPHA +MAPNIK_DECL void set_grayscale_to_alpha (image_any & image); +MAPNIK_DECL void set_grayscale_to_alpha (image_any & image, color const& c); + +template +MAPNIK_DECL void set_grayscale_to_alpha (T & image); + +template +MAPNIK_DECL void set_grayscale_to_alpha (T & image, color const& c); + +// SET COLOR TO ALPHA +MAPNIK_DECL void set_color_to_alpha (image_any & image, color const& c); + +template +MAPNIK_DECL void set_color_to_alpha (T & image, color const& c); + +// FILL +template +MAPNIK_DECL void fill (image_any & data, T const&); + +template +MAPNIK_DECL void fill (image_rgba8 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray8 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray8s & data, T const&); + +template +MAPNIK_DECL void fill (image_gray16 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray16s & data, T const&); + +template +MAPNIK_DECL void fill (image_gray32 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray32s & data, T const&); + +template +MAPNIK_DECL void fill (image_gray32f & data, T const&); + +template +MAPNIK_DECL void fill (image_gray64 & data, T const&); + +template +MAPNIK_DECL void fill (image_gray64s & data, T const&); + +template +MAPNIK_DECL void fill (image_gray64f & data, T const&); + +// SET RECTANGLE +MAPNIK_DECL void set_rectangle (image_any & dst, image_any const& src, int x = 0, int y = 0); + +template +MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x = 0, int y = 0); + +// CHECK BOUNDS +template +inline bool check_bounds (T const& data, std::size_t x, std::size_t y) +{ + return (x < static_cast(data.width()) && y < static_cast(data.height())); +} + +// COMPOSITE_PIXEL +MAPNIK_DECL void composite_pixel(image_any & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ); + +template +MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ); + +// SET PIXEL +template +MAPNIK_DECL void set_pixel(image_any & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_rgba8 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray8 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray8s & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray16 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray16s & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray32 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray32s & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray32f & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray64 & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray64s & data, std::size_t x, std::size_t y, T const& val); + +template +MAPNIK_DECL void set_pixel(image_gray64f & data, std::size_t x, std::size_t y, T const& val); + +// GET PIXEL +template +MAPNIK_DECL T get_pixel(image_any const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_any const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_rgba8 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray8 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray8s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray16 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray16s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray32 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray32s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray32f const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray64 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray64s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_gray64f const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_rgba8 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray8 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray8s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray16 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray16s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray32 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray32s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray32f const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray64 const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray64s const& data, std::size_t x, std::size_t y); + +template +MAPNIK_DECL T get_pixel(image_view_gray64f const& data, std::size_t x, std::size_t y); + +// VIEW TO STRING +MAPNIK_DECL void view_to_string (image_view_any const& view, std::ostringstream & ss); + +// CREATE VIEW +MAPNIK_DECL image_view_any create_view (image_any const& data, unsigned x, unsigned y, unsigned w, unsigned h); + +// COMPARE +template +MAPNIK_DECL unsigned compare(T const& im1, T const& im2, double threshold = 0, bool alpha = true); inline bool is_png(std::string const& filename) { @@ -209,82 +409,6 @@ void add_border(T & image) } } - -extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, - std::string const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, - std::string const&, - std::string const&); - -extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file(image_data_rgba8 const&, - std::string const&); - - -extern template MAPNIK_DECL void save_to_file > (image_view const&, - std::string const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file > (image_view const&, - std::string const&, - std::string const&); - -extern template MAPNIK_DECL void save_to_file > (image_view const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL void save_to_file > (image_view const&, - std::string const&); - -extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, - std::string const&); - -extern template MAPNIK_DECL std::string save_to_string(image_data_rgba8 const&, - std::string const&, - rgba_palette const&); - -extern template MAPNIK_DECL std::string save_to_string > (image_view const&, - std::string const&); - -extern template MAPNIK_DECL std::string save_to_string > (image_view const&, - std::string const&, - rgba_palette const&); -#ifdef _MSC_VER - -template MAPNIK_DECL void save_to_stream( - image_data_rgba8 const& image, - std::ostream & stream, - std::string const& type, - rgba_palette const& palette -); - -template MAPNIK_DECL void save_to_stream( - image_data_rgba8 const& image, - std::ostream & stream, - std::string const& type -); - -template MAPNIK_DECL void save_to_stream > ( - image_view const& image, - std::ostream & stream, - std::string const& type, - rgba_palette const& palette -); - -template MAPNIK_DECL void save_to_stream > ( - image_view const& image, - std::ostream & stream, - std::string const& type -); -#endif - } #endif // MAPNIK_IMAGE_UTIL_HPP diff --git a/include/mapnik/image_util_jpeg.hpp b/include/mapnik/image_util_jpeg.hpp new file mode 100644 index 000000000..5f77f56f0 --- /dev/null +++ b/include/mapnik/image_util_jpeg.hpp @@ -0,0 +1,44 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_IMAGE_UTIL_JPEG_HPP +#define MAPNIK_IMAGE_UTIL_JPEG_HPP + +// stl +#include +#include + +namespace mapnik { + +struct jpeg_saver +{ + jpeg_saver(std::ostream &, std::string const&); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_JPEG_HPP diff --git a/include/mapnik/image_util_png.hpp b/include/mapnik/image_util_png.hpp new file mode 100644 index 000000000..06dcde894 --- /dev/null +++ b/include/mapnik/image_util_png.hpp @@ -0,0 +1,55 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_IMAGE_UTIL_PNG_HPP +#define MAPNIK_IMAGE_UTIL_PNG_HPP + +// stl +#include +#include + +namespace mapnik { + +struct png_saver_pal +{ + png_saver_pal(std::ostream &, std::string const&, rgba_palette const&); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; + rgba_palette const& pal_; +}; + +struct png_saver +{ + png_saver(std::ostream &, std::string const&); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_PNG_HPP diff --git a/include/mapnik/image_util_tiff.hpp b/include/mapnik/image_util_tiff.hpp new file mode 100644 index 000000000..5cacc6781 --- /dev/null +++ b/include/mapnik/image_util_tiff.hpp @@ -0,0 +1,44 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_IMAGE_UTIL_TIFF_HPP +#define MAPNIK_IMAGE_UTIL_TIFF_HPP + +// stl +#include +#include + +namespace mapnik { + +struct tiff_saver +{ + tiff_saver(std::ostream &, std::string const&); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_TIFF_HPP diff --git a/include/mapnik/image_util_webp.hpp b/include/mapnik/image_util_webp.hpp new file mode 100644 index 000000000..14a218309 --- /dev/null +++ b/include/mapnik/image_util_webp.hpp @@ -0,0 +1,44 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_IMAGE_UTIL_WEBP_HPP +#define MAPNIK_IMAGE_UTIL_WEBP_HPP + +// stl +#include +#include + +namespace mapnik { + +struct webp_saver +{ + webp_saver(std::ostream &, std::string const&); + template + void operator() (T const&) const; + private: + std::ostream & stream_; + std::string const& t_; +}; + +} // end ns + +#endif // MAPNIK_IMAGE_UTIL_WEBP_HPP diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 3daed9e31..640235ac5 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -23,12 +23,15 @@ #ifndef MAPNIK_IMAGE_VIEW_HPP #define MAPNIK_IMAGE_VIEW_HPP +#include + namespace mapnik { template class image_view { public: + using pixel = typename T::pixel; using pixel_type = typename T::pixel_type; static constexpr std::size_t pixel_size = sizeof(pixel_type); @@ -84,6 +87,10 @@ public: { return height_; } + inline const pixel_type& operator() (std::size_t i, std::size_t j) const + { + return data_(i,j); + } inline unsigned getSize() const { @@ -110,6 +117,21 @@ public: return data_; } + inline bool get_premultiplied() const + { + return data_.get_premultiplied(); + } + + inline double get_offset() const + { + return data_.get_offset(); + } + + inline double get_scaling() const + { + return data_.get_scaling(); + } + private: unsigned x_; unsigned y_; @@ -117,6 +139,19 @@ private: unsigned height_; T const& data_; }; -} + +using image_view_rgba8 = image_view; +using image_view_gray8 = image_view; +using image_view_gray8s = image_view; +using image_view_gray16 = image_view; +using image_view_gray16s = image_view; +using image_view_gray32 = image_view; +using image_view_gray32s = image_view; +using image_view_gray32f = image_view; +using image_view_gray64 = image_view; +using image_view_gray64s = image_view; +using image_view_gray64f = image_view; + +} // end ns #endif // MAPNIK_IMAGE_VIEW_HPP diff --git a/include/mapnik/image_view_any.hpp b/include/mapnik/image_view_any.hpp new file mode 100644 index 000000000..9f47f0ae4 --- /dev/null +++ b/include/mapnik/image_view_any.hpp @@ -0,0 +1,155 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_IMAGE_VIEW_ANY_HPP +#define MAPNIK_IMAGE_VIEW_ANY_HPP + +#include +#include + +namespace mapnik { + +using image_view_base = util::variant; + +namespace detail { + +struct get_view_width_visitor +{ + template + std::size_t operator()(T const& data) const + { + return data.width(); + } +}; + +struct get_view_height_visitor +{ + template + std::size_t operator()(T const& data) const + { + return data.height(); + } +}; + +struct get_view_size_visitor +{ + template + unsigned operator()(T const& data) const + { + return data.getSize(); + } +}; + +struct get_view_row_size_visitor +{ + template + unsigned operator()(T const& data) const + { + return data.getRowSize(); + } +}; + +struct get_view_premultiplied_visitor +{ + template + bool operator()(T const& data) const + { + return data.get_premultiplied(); + } +}; + +struct get_view_offset_visitor +{ + template + double operator()(T const& data) const + { + return data.get_offset(); + } +}; + +struct get_view_scaling_visitor +{ + template + double operator()(T const& data) const + { + return data.get_scaling(); + } +}; +} // namespace detail + +struct image_view_any : image_view_base +{ + image_view_any() = default; + + template + image_view_any(T && data) noexcept + : image_view_base(std::move(data)) {} + + std::size_t width() const + { + return util::apply_visitor(detail::get_view_width_visitor(),*this); + } + + std::size_t height() const + { + return util::apply_visitor(detail::get_view_height_visitor(),*this); + } + + unsigned getSize() const + { + return util::apply_visitor(detail::get_view_size_visitor(),*this); + } + + unsigned getRowSize() const + { + return util::apply_visitor(detail::get_view_row_size_visitor(),*this); + } + + bool get_premultiplied() const + { + return util::apply_visitor(detail::get_view_premultiplied_visitor(),*this); + } + + double get_offset() const + { + return util::apply_visitor(detail::get_view_offset_visitor(),*this); + } + + double get_scaling() const + { + return util::apply_visitor(detail::get_view_scaling_visitor(),*this); + } +}; + +} + +#endif // MAPNIK_IMAGE_VIEW_ANY_HPP diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index 63fe16c18..9b57b014a 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -24,11 +24,13 @@ #define MAPNIK_MARKER_HPP // mapnik -#include +#include +#include #include #include #include #include +#include // agg #include "agg_array.h" @@ -45,97 +47,169 @@ namespace mapnik using attr_storage = agg::pod_bvector; using svg_storage_type = mapnik::svg::svg_storage; using svg_path_ptr = std::shared_ptr; -using image_ptr = std::shared_ptr; -/** - * A class to hold either vector or bitmap marker data. This allows these to be treated equally - * in the image caches and most of the render paths. - */ -class marker: private util::noncopyable +using image_ptr = std::shared_ptr; + +struct marker_rgba8 { public: - marker() + marker_rgba8() + : bitmap_data_(4,4,true,true) { // create default OGC 4x4 black pixel - bitmap_data_ = boost::optional(std::make_shared(4,4)); - (*bitmap_data_)->set(0xff000000); + bitmap_data_.set(0xff000000); } - marker(boost::optional const& data) + marker_rgba8(image_rgba8 const & data) : bitmap_data_(data) {} + + marker_rgba8(image_rgba8 && data) + : bitmap_data_(std::move(data)) {} - marker(boost::optional const& data) - : vector_data_(data) {} + marker_rgba8(marker_rgba8 const& rhs) + : bitmap_data_(rhs.bitmap_data_) {} - marker(marker const& rhs) - : bitmap_data_(rhs.bitmap_data_), - vector_data_(rhs.vector_data_) {} + marker_rgba8(marker_rgba8 && rhs) noexcept + : bitmap_data_(std::move(rhs.bitmap_data_)) {} box2d bounding_box() const { - if (is_vector()) - { - return (*vector_data_)->bounding_box(); - } - if (is_bitmap()) - { - double width = (*bitmap_data_)->width(); - double height = (*bitmap_data_)->height(); - return box2d(0, 0, width, height); - } - return box2d(); + double width = bitmap_data_.width(); + double height = bitmap_data_.height(); + return box2d(0, 0, width, height); } - inline double width() const + inline std::size_t width() const { - if (is_bitmap()) - { - return (*bitmap_data_)->width(); - } - else if (is_vector()) - { - return (*vector_data_)->bounding_box().width(); - } - return 0; - } - inline double height() const - { - if (is_bitmap()) - { - return (*bitmap_data_)->height(); - } - else if (is_vector()) - { - return (*vector_data_)->bounding_box().height(); - } - return 0; + return bitmap_data_.width(); } - inline bool is_bitmap() const + inline std::size_t height() const { - return !!bitmap_data_; + return bitmap_data_.height(); } - inline bool is_vector() const - { - return !!vector_data_; - } - - boost::optional get_bitmap_data() const + image_rgba8 const& get_data() const { return bitmap_data_; } - boost::optional get_vector_data() const +private: + image_rgba8 bitmap_data_; +}; + +struct marker_svg +{ +public: + marker_svg() { } + + marker_svg(mapnik::svg_path_ptr data) + : vector_data_(data) {} + + marker_svg(marker_svg const& rhs) + : vector_data_(rhs.vector_data_) {} + + marker_svg(marker_svg && rhs) noexcept + : vector_data_(rhs.vector_data_) {} + + box2d bounding_box() const + { + return vector_data_->bounding_box(); + } + + inline double width() const + { + return vector_data_->bounding_box().width(); + } + inline double height() const + { + return vector_data_->bounding_box().height(); + } + + mapnik::svg_path_ptr get_data() const { return vector_data_; } private: - boost::optional bitmap_data_; - boost::optional vector_data_; + mapnik::svg_path_ptr vector_data_; }; -} +struct marker_null +{ +public: + box2d bounding_box() const + { + return box2d(); + } + inline double width() const + { + return 0; + } + inline double height() const + { + return 0; + } +}; + +using marker_base = util::variant; +namespace detail { + +struct get_marker_bbox_visitor +{ + template + box2d operator()(T & data) const + { + return data.bounding_box(); + } +}; + +struct get_marker_width_visitor +{ + template + double operator()(T const& data) const + { + return static_cast(data.width()); + } +}; + +struct get_marker_height_visitor +{ + template + double operator()(T const& data) const + { + return static_cast(data.height()); + } +}; + +} // end detail ns + +struct marker : marker_base +{ + marker() = default; + + template + marker(T && data) noexcept + : marker_base(std::move(data)) {} + + double width() const + { + return util::apply_visitor(detail::get_marker_width_visitor(),*this); + } + + double height() const + { + return util::apply_visitor(detail::get_marker_height_visitor(),*this); + } + + box2d bounding_box() const + { + return util::apply_visitor(detail::get_marker_bbox_visitor(),*this); + } +}; + +} // end mapnik ns #endif // MAPNIK_MARKER_HPP diff --git a/include/mapnik/marker_cache.hpp b/include/mapnik/marker_cache.hpp index 34907cc80..40cf8048f 100644 --- a/include/mapnik/marker_cache.hpp +++ b/include/mapnik/marker_cache.hpp @@ -36,10 +36,7 @@ namespace mapnik { -class marker; - -using marker_ptr = std::shared_ptr; - +struct marker; class MAPNIK_DECL marker_cache : public singleton , @@ -49,8 +46,8 @@ class MAPNIK_DECL marker_cache : private: marker_cache(); ~marker_cache(); - bool insert_marker(std::string const& key, marker_ptr path); - boost::unordered_map marker_cache_; + bool insert_marker(std::string const& key, marker && path); + boost::unordered_map marker_cache_; bool insert_svg(std::string const& name, std::string const& svg_string); boost::unordered_map svg_cache_; public: @@ -59,7 +56,7 @@ public: inline bool is_uri(std::string const& path) { return is_svg_uri(path) || is_image_uri(path); } bool is_svg_uri(std::string const& path); bool is_image_uri(std::string const& path); - boost::optional find(std::string const& key, bool update_cache = false); + marker const& find(std::string const& key, bool update_cache = false); void clear(); }; diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 48d3b82b1..1f03b117b 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -118,7 +118,7 @@ protected: template struct raster_markers_dispatch : util::noncopyable { - raster_markers_dispatch(image_data_rgba8 & src, + raster_markers_dispatch(image_rgba8 const& src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -163,7 +163,7 @@ struct raster_markers_dispatch : util::noncopyable virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0; protected: - image_data_rgba8 & src_; + image_rgba8 const& src_; agg::trans_affine const& marker_trans_; symbolizer_base const& sym_; Detector & detector_; diff --git a/include/mapnik/miniz_png.hpp b/include/mapnik/miniz_png.hpp index bc9221f36..0414c329c 100644 --- a/include/mapnik/miniz_png.hpp +++ b/include/mapnik/miniz_png.hpp @@ -32,7 +32,7 @@ #include #include -#include +#include #include /* miniz.c porting issues: @@ -83,12 +83,12 @@ private: static const unsigned char IEND_tpl[]; }; -extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_data_gray8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT >(image_view const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_data_rgba8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDAT >(image_view const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_data_rgba8 const& image); -extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha >(image_view const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_gray8 const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_gray8 const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_rgba8 const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDAT(image_view_rgba8 const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_rgba8 const& image); +extern template MAPNIK_DECL void PNGWriter::writeIDATStripAlpha(image_view_rgba8 const& image); }} diff --git a/include/mapnik/pixel_types.hpp b/include/mapnik/pixel_types.hpp new file mode 100644 index 000000000..aef5dca8c --- /dev/null +++ b/include/mapnik/pixel_types.hpp @@ -0,0 +1,40 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_PIXEL_TYPES_HPP +#define MAPNIK_PIXEL_TYPES_HPP + +#include + +struct rgba8_t { using type = std::uint32_t; }; +struct gray8_t { using type = std::uint8_t; }; +struct gray8s_t { using type = std::int8_t; }; +struct gray16_t { using type = std::uint16_t; }; +struct gray16s_t { using type = std::int16_t; }; +struct gray32_t { using type = std::uint32_t; }; +struct gray32s_t { using type = std::int32_t; }; +struct gray32f_t { using type = float; }; +struct gray64_t { using type = std::uint64_t; }; +struct gray64s_t { using type = std::int64_t; }; +struct gray64f_t { using type = double; }; + +#endif // MAPNIK_PIXEL_TYPES_HPP diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp index 88821eb87..f6df24fbf 100644 --- a/include/mapnik/png_io.hpp +++ b/include/mapnik/png_io.hpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include // zlib #include // for Z_DEFAULT_COMPRESSION @@ -149,7 +149,7 @@ void save_as_png(T1 & file, template void reduce_8(T const& in, - image_data_gray8 & out, + image_gray8 & out, octree trees[], unsigned limits[], unsigned levels, @@ -166,8 +166,8 @@ void reduce_8(T const& in, } for (unsigned y = 0; y < height; ++y) { - mapnik::image_data_rgba8::pixel_type const * row = in.getRow(y); - mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y); + mapnik::image_rgba8::pixel_type const * row = in.getRow(y); + mapnik::image_gray8::pixel_type * row_out = out.getRow(y); for (unsigned x = 0; x < width; ++x) { unsigned val = row[x]; @@ -200,7 +200,7 @@ void reduce_8(T const& in, template void reduce_4(T const& in, - image_data_gray8 & out, + image_gray8 & out, octree trees[], unsigned limits[], unsigned levels, @@ -217,8 +217,8 @@ void reduce_4(T const& in, } for (unsigned y = 0; y < height; ++y) { - mapnik::image_data_rgba8::pixel_type const * row = in.getRow(y); - mapnik::image_data_gray8::pixel_type * row_out = out.getRow(y); + mapnik::image_rgba8::pixel_type const * row = in.getRow(y); + mapnik::image_gray8::pixel_type * row_out = out.getRow(y); for (unsigned x = 0; x < width; ++x) { unsigned val = row[x]; @@ -256,7 +256,7 @@ void reduce_4(T const& in, // 1-bit but only one color. template void reduce_1(T const&, - image_data_gray8 & out, + image_gray8 & out, octree /*trees*/[], unsigned /*limits*/[], std::vector & /*alpha*/) @@ -266,7 +266,7 @@ void reduce_1(T const&, template void save_as_png(T & file, std::vector const& palette, - mapnik::image_data_gray8 const& image, + mapnik::image_gray8 const& image, unsigned width, unsigned height, unsigned color_depth, @@ -556,7 +556,7 @@ void save_as_png8_oct(T1 & file, if (palette.size() > 16 ) { // >16 && <=256 colors -> write 8-bit color depth - image_data_gray8 reduced_image(width,height); + image_gray8 reduced_image(width,height); reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable); save_as_png(file,palette,reduced_image,width,height,8,alphaTable,opts); } @@ -565,7 +565,7 @@ void save_as_png8_oct(T1 & file, // 1 color image -> write 1-bit color depth PNG unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary unsigned image_height = height; - image_data_gray8 reduced_image(image_width,image_height); + image_gray8 reduced_image(image_width,image_height); reduce_1(image,reduced_image,trees, limits, alphaTable); if (meanAlpha<255 && cols[0]==0) { @@ -579,7 +579,7 @@ void save_as_png8_oct(T1 & file, // <=16 colors -> write 4-bit color depth PNG unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary unsigned image_height = height; - image_data_gray8 reduced_image(image_width,image_height); + image_gray8 reduced_image(image_width,image_height); reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable); save_as_png(file,palette,reduced_image,width,height,4,alphaTable,opts); } @@ -600,11 +600,11 @@ void save_as_png8(T1 & file, if (palette.size() > 16 ) { // >16 && <=256 colors -> write 8-bit color depth - image_data_gray8 reduced_image(width, height); + image_gray8 reduced_image(width, height); for (unsigned y = 0; y < height; ++y) { - mapnik::image_data_rgba8::pixel_type const * row = image.getRow(y); - mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); + mapnik::image_rgba8::pixel_type const * row = image.getRow(y); + mapnik::image_gray8::pixel_type * row_out = reduced_image.getRow(y); for (unsigned x = 0; x < width; ++x) { row_out[x] = tree.quantize(row[x]); @@ -617,7 +617,7 @@ void save_as_png8(T1 & file, // 1 color image -> write 1-bit color depth PNG unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary unsigned image_height = height; - image_data_gray8 reduced_image(image_width, image_height); + image_gray8 reduced_image(image_width, image_height); reduced_image.set(0); save_as_png(file, palette, reduced_image, width, height, 1, alphaTable, opts); } @@ -626,11 +626,11 @@ void save_as_png8(T1 & file, // <=16 colors -> write 4-bit color depth PNG unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary unsigned image_height = height; - image_data_gray8 reduced_image(image_width, image_height); + image_gray8 reduced_image(image_width, image_height); for (unsigned y = 0; y < height; ++y) { - mapnik::image_data_rgba8::pixel_type const * row = image.getRow(y); - mapnik::image_data_gray8::pixel_type * row_out = reduced_image.getRow(y); + mapnik::image_rgba8::pixel_type const * row = image.getRow(y); + mapnik::image_gray8::pixel_type * row_out = reduced_image.getRow(y); byte index = 0; for (unsigned x = 0; x < width; ++x) { diff --git a/include/mapnik/raster.hpp b/include/mapnik/raster.hpp index 8fafd27b2..a4b26cb63 100644 --- a/include/mapnik/raster.hpp +++ b/include/mapnik/raster.hpp @@ -25,7 +25,7 @@ // mapnik #include -#include +#include #include #include // boost @@ -37,20 +37,17 @@ class raster : private util::noncopyable { public: box2d ext_; - image_data_any data_; + image_any data_; double filter_factor_; - bool premultiplied_alpha_; boost::optional nodata_; template raster(box2d const& ext, ImageData && data, - double filter_factor, - bool premultiplied_alpha = false) + double filter_factor) : ext_(ext), data_(std::move(data)), - filter_factor_(filter_factor), - premultiplied_alpha_(premultiplied_alpha) {} + filter_factor_(filter_factor) {} void set_nodata(double nodata) { diff --git a/include/mapnik/raster_colorizer.hpp b/include/mapnik/raster_colorizer.hpp index fe66769b8..63e2d0727 100644 --- a/include/mapnik/raster_colorizer.hpp +++ b/include/mapnik/raster_colorizer.hpp @@ -40,7 +40,7 @@ #include #include #include -#include +#include // boost #include // boost @@ -198,7 +198,7 @@ public: colorizer_stops const& get_stops() const { return stops_; } template - void colorize(image_data_rgba8 & out, T const& in, boost::optionalconst& nodata, feature_impl const& f) const; + void colorize(image_rgba8 & out, T const& in, boost::optionalconst& nodata, feature_impl const& f) const; //! \brief Perform the translation of input to output //! diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp index 348302ef8..d1dbcf474 100644 --- a/include/mapnik/renderer_common/process_group_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp @@ -42,7 +42,6 @@ #include #include #include -#include // agg #include @@ -130,13 +129,13 @@ struct vector_marker_render_thunk : util::noncopyable struct raster_marker_render_thunk : util::noncopyable { - image_data_rgba8 & src_; + image_rgba8 const& src_; agg::trans_affine tr_; double opacity_; composite_mode_e comp_op_; bool snap_to_pixels_; - raster_marker_render_thunk(image_data_rgba8 & src, + raster_marker_render_thunk(image_rgba8 const& src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, diff --git a/include/mapnik/renderer_common/process_markers_symbolizer.hpp b/include/mapnik/renderer_common/process_markers_symbolizer.hpp index f62687ab9..996867efc 100644 --- a/include/mapnik/renderer_common/process_markers_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_markers_symbolizer.hpp @@ -32,6 +32,230 @@ namespace mapnik { +template +struct render_marker_symbolizer_visitor +{ + using vector_dispatch_type = VD; + using raster_dispatch_type = RD; + using buffer_type = typename std::tuple_element<0,ContextType>::type; + + render_marker_symbolizer_visitor(std::string const& filename, + markers_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans, + RendererType const& common, + box2d const& clip_box, + ContextType const& renderer_context) + : filename_(filename), + sym_(sym), + feature_(feature), + prj_trans_(prj_trans), + common_(common), + clip_box_(clip_box), + renderer_context_(renderer_context) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& mark) + { + using namespace mapnik::svg; + bool clip = get(sym_, feature_, common_.vars_); + double offset = get(sym_, feature_, common_.vars_); + double simplify_tolerance = get(sym_, feature_, common_.vars_); + double smooth = get(sym_, feature_, common_.vars_); + + // https://github.com/mapnik/mapnik/issues/1316 + bool snap_to_pixels = !mapnik::marker_cache::instance().is_uri(filename_); + + agg::trans_affine geom_tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(geom_tr, feature_, common_.vars_, *transform, common_.scale_factor_); + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + + boost::optional const& stock_vector_marker = mark.get_data(); + + // special case for simple ellipse markers + // to allow for full control over rx/ry dimensions + if (filename_ == "shape://ellipse" + && (has_key(sym_,keys::width) || has_key(sym_,keys::height))) + { + svg_path_ptr marker_ellipse = std::make_shared(); + vertex_stl_adapter stl_storage(marker_ellipse->source()); + svg_path_adapter svg_path(stl_storage); + build_ellipse(sym_, feature_, common_.vars_, *marker_ellipse, svg_path); + svg_attribute_type attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym_, feature_, common_.vars_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + vector_dispatch_type rasterizer_dispatch(marker_ellipse, + svg_path, + result ? attributes : (*stock_vector_marker)->attributes(), + image_tr, + sym_, + *common_.detector_, + common_.scale_factor_, + feature_, + common_.vars_, + snap_to_pixels, + renderer_context_); + + using vertex_converter_type = vertex_converter; + vertex_converter_type converter(clip_box_, + rasterizer_dispatch, + sym_, + common_.t_, + prj_trans_, + geom_tr, + feature_, + common_.vars_, + common_.scale_factor_); + if (clip && feature_.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature_.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + else if (type == geometry_type::types::LineString) + converter.template set(); + } + converter.template set(); //always transform + if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset + converter.template set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature_, common_.vars_, converter, sym_); + } + else + { + box2d const& bbox = mark.bounding_box(); + setup_transform_scaling(image_tr, bbox.width(), bbox.height(), feature_, common_.vars_, sym_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); + svg_path_adapter svg_path(stl_storage); + svg_attribute_type attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym_, feature_, common_.vars_); + vector_dispatch_type rasterizer_dispatch(*stock_vector_marker, + svg_path, + result ? attributes : (*stock_vector_marker)->attributes(), + image_tr, + sym_, + *common_.detector_, + common_.scale_factor_, + feature_, + common_.vars_, + snap_to_pixels, + renderer_context_); + + using vertex_converter_type = vertex_converter; + vertex_converter_type converter(clip_box_, + rasterizer_dispatch, + sym_, + common_.t_, + prj_trans_, + geom_tr, + feature_, + common_.vars_, + common_.scale_factor_); + if (clip && feature_.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature_.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + else if (type == geometry_type::types::LineString) + converter.template set(); + } + converter.template set(); //always transform + if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset + converter.template set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature_, common_.vars_, converter, sym_); + } + } + + void operator() (marker_rgba8 const& mark) + { + using namespace mapnik::svg; + bool clip = get(sym_, feature_, common_.vars_); + double offset = get(sym_, feature_, common_.vars_); + double simplify_tolerance = get(sym_, feature_, common_.vars_); + double smooth = get(sym_, feature_, common_.vars_); + + agg::trans_affine geom_tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(geom_tr, feature_, common_.vars_, *transform, common_.scale_factor_); + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + + setup_transform_scaling(image_tr, mark.width(), mark.height(), feature_, common_.vars_, sym_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + box2d const& bbox = mark.bounding_box(); + mapnik::image_rgba8 const& marker = mark.get_data(); + // - clamp sizes to > 4 pixels of interactivity + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * image_tr; + raster_dispatch_type rasterizer_dispatch(marker, + marker_trans, + sym_, + *common_.detector_, + common_.scale_factor_, + feature_, + common_.vars_, + renderer_context_); + + using vertex_converter_type = vertex_converter; + vertex_converter_type converter(clip_box_, + rasterizer_dispatch, + sym_, + common_.t_, + prj_trans_, + geom_tr, + feature_, + common_.vars_, + common_.scale_factor_); + + if (clip && feature_.paths().size() > 0) // optional clip (default: true) + { + geometry_type::types type = feature_.paths()[0].type(); + if (type == geometry_type::types::Polygon) + converter.template set(); + else if (type == geometry_type::types::LineString) + converter.template set(); + } + converter.template set(); //always transform + if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset + converter.template set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter + if (smooth > 0.0) converter.template set(); // optional smooth converter + apply_markers_multi(feature_, common_.vars_, converter, sym_); + } + + private: + std::string const& filename_; + markers_symbolizer const& sym_; + mapnik::feature_impl & feature_; + proj_transform const& prj_trans_; + RendererType const& common_; + box2d const& clip_box_; + ContextType const& renderer_context_; +}; + template void render_markers_symbolizer(markers_symbolizer const& sym, mapnik::feature_impl & feature, @@ -41,167 +265,18 @@ void render_markers_symbolizer(markers_symbolizer const& sym, ContextType const& renderer_context) { using namespace mapnik::svg; - using vector_dispatch_type = VD; - using raster_dispatch_type = RD; - std::string filename = get(sym, keys::file, feature, common.vars_, "shape://ellipse"); - bool clip = get(sym, feature, common.vars_); - double offset = get(sym, feature, common.vars_); - double simplify_tolerance = get(sym, feature, common.vars_); - double smooth = get(sym, feature, common.vars_); - - // https://github.com/mapnik/mapnik/issues/1316 - bool snap_to_pixels = !mapnik::marker_cache::instance().is_uri(filename); if (!filename.empty()) { - boost::optional mark = mapnik::marker_cache::instance().find(filename, true); - if (mark && *mark) - { - agg::trans_affine geom_tr; - auto transform = get_optional(sym, keys::geometry_transform); - if (transform) evaluate_transform(geom_tr, feature, common.vars_, *transform, common.scale_factor_); - agg::trans_affine image_tr = agg::trans_affine_scaling(common.scale_factor_); - - if ((*mark)->is_vector()) - { - boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); - - // special case for simple ellipse markers - // to allow for full control over rx/ry dimensions - if (filename == "shape://ellipse" - && (has_key(sym,keys::width) || has_key(sym,keys::height))) - { - svg_path_ptr marker_ellipse = std::make_shared(); - vertex_stl_adapter stl_storage(marker_ellipse->source()); - svg_path_adapter svg_path(stl_storage); - build_ellipse(sym, feature, common.vars_, *marker_ellipse, svg_path); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym, feature, common.vars_); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform); - vector_dispatch_type rasterizer_dispatch(marker_ellipse, - svg_path, - result ? attributes : (*stock_vector_marker)->attributes(), - image_tr, - sym, - *common.detector_, - common.scale_factor_, - feature, - common.vars_, - snap_to_pixels, - renderer_context); - - using vertex_converter_type = vertex_converter; - vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - else if (type == geometry_type::types::LineString) - converter.template set(); - } - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, common.vars_, converter, sym); - } - else - { - box2d const& bbox = (*mark)->bounding_box(); - setup_transform_scaling(image_tr, bbox.width(), bbox.height(), feature, common.vars_, sym); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform); - vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); - svg_path_adapter svg_path(stl_storage); - svg_attribute_type attributes; - bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym, feature, common.vars_); - vector_dispatch_type rasterizer_dispatch(*stock_vector_marker, - svg_path, - result ? attributes : (*stock_vector_marker)->attributes(), - image_tr, - sym, - *common.detector_, - common.scale_factor_, - feature, - common.vars_, - snap_to_pixels, - renderer_context); - - using vertex_converter_type = vertex_converter; - vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_); - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - else if (type == geometry_type::types::LineString) - converter.template set(); - } - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, common.vars_, converter, sym); - } - } - else // raster markers - { - setup_transform_scaling(image_tr, (*mark)->width(), (*mark)->height(), feature, common.vars_, sym); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common.vars_, *image_transform); - box2d const& bbox = (*mark)->bounding_box(); - boost::optional marker = (*mark)->get_bitmap_data(); - // - clamp sizes to > 4 pixels of interactivity - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * image_tr; - raster_dispatch_type rasterizer_dispatch(**marker, - marker_trans, - sym, - *common.detector_, - common.scale_factor_, - feature, - common.vars_, - renderer_context); - - using vertex_converter_type = vertex_converter; - vertex_converter_type converter(clip_box, rasterizer_dispatch, sym,common.t_,prj_trans,geom_tr,feature,common.vars_,common.scale_factor_); - - if (clip && feature.paths().size() > 0) // optional clip (default: true) - { - geometry_type::types type = feature.paths()[0].type(); - if (type == geometry_type::types::Polygon) - converter.template set(); - else if (type == geometry_type::types::LineString) - converter.template set(); - } - converter.template set(); //always transform - if (std::fabs(offset) > 0.0) converter.template set(); // parallel offset - converter.template set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.template set(); // optional simplify converter - if (smooth > 0.0) converter.template set(); // optional smooth converter - apply_markers_multi(feature, common.vars_, converter, sym); - } - } + mapnik::marker const& mark = mapnik::marker_cache::instance().find(filename, true); + render_marker_symbolizer_visitor visitor(filename, + sym, + feature, + prj_trans, + common, + clip_box, + renderer_context); + util::apply_visitor(visitor, mark); } } diff --git a/include/mapnik/renderer_common/process_point_symbolizer.hpp b/include/mapnik/renderer_common/process_point_symbolizer.hpp index 9030aab9d..4fd3df6b8 100644 --- a/include/mapnik/renderer_common/process_point_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_point_symbolizer.hpp @@ -41,18 +41,18 @@ void render_point_symbolizer(point_symbolizer const &sym, F render_marker) { std::string filename = get(sym,feature, common.vars_); - boost::optional marker = filename.empty() - ? std::make_shared() + mapnik::marker const& mark = filename.empty() + ? mapnik::marker(std::move(mapnik::marker_rgba8())) : marker_cache::instance().find(filename, true); - if (marker) + if (!mark.is()) { value_double opacity = get(sym, feature, common.vars_); value_bool allow_overlap = get(sym, feature, common.vars_); value_bool ignore_placement = get(sym, feature, common.vars_); point_placement_enum placement= get(sym, feature, common.vars_); - box2d const& bbox = (*marker)->bounding_box(); + box2d const& bbox = mark.bounding_box(); coord2d center = bbox.center(); agg::trans_affine tr; @@ -89,7 +89,7 @@ void render_point_symbolizer(point_symbolizer const &sym, { render_marker(pixel_position(x, y), - **marker, + mark, tr, opacity); diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp index 7229c60f2..3ef8b19cb 100644 --- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp @@ -24,6 +24,7 @@ #define MAPNIK_RENDERER_COMMON_PROCESS_RASTER_SYMBOLIZER_HPP // mapnik +#include #include #include #include @@ -44,10 +45,10 @@ namespace mapnik { namespace detail { template -struct image_data_dispatcher +struct image_dispatcher { using composite_function = F; - image_data_dispatcher(int start_x, int start_y, + image_dispatcher(int start_x, int start_y, int width, int height, double scale_x, double scale_y, scaling_method_e method, double filter_factor, @@ -68,10 +69,10 @@ struct image_data_dispatcher composite_(composite), nodata_(nodata) {} - void operator() (image_data_null const& data_in) const {} //no-op - void operator() (image_data_rgba8 const& data_in) const + void operator() (image_null const& data_in) const {} //no-op + void operator() (image_rgba8 const& data_in) const { - image_data_rgba8 data_out(width_, height_); + image_rgba8 data_out(width_, height_, true, true); scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_); composite_(data_out, comp_op_, opacity_, start_x_, start_y_); } @@ -79,12 +80,13 @@ struct image_data_dispatcher template void operator() (T const& data_in) const { - using image_data_type = T; - image_data_type data_out(width_, height_); + using image_type = T; + image_type data_out(width_, height_); scale_image_agg(data_out, data_in, method_, scale_x_, scale_y_, 0.0, 0.0, filter_factor_); - image_data_rgba8 dst(width_, height_); + image_rgba8 dst(width_, height_); raster_colorizer_ptr colorizer = get(sym_, keys::colorizer); if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_); + premultiply_alpha(dst); composite_(dst, comp_op_, opacity_, start_x_, start_y_); } private: @@ -105,10 +107,10 @@ private: }; template -struct image_data_warp_dispatcher +struct image_warp_dispatcher { using composite_function = F; - image_data_warp_dispatcher(proj_transform const& prj_trans, + image_warp_dispatcher(proj_transform const& prj_trans, int start_x, int start_y, int width, int height, box2d const& target_ext, box2d const& source_ext, double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, @@ -133,11 +135,11 @@ struct image_data_warp_dispatcher composite_(composite), nodata_(nodata) {} - void operator() (image_data_null const& data_in) const {} //no-op + void operator() (image_null const& data_in) const {} //no-op - void operator() (image_data_rgba8 const& data_in) const + void operator() (image_rgba8 const& data_in) const { - image_data_rgba8 data_out(width_, height_); + image_rgba8 data_out(width_, height_, true, true); warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_); composite_(data_out, comp_op_, opacity_, start_x_, start_y_); } @@ -145,13 +147,14 @@ struct image_data_warp_dispatcher template void operator() (T const& data_in) const { - using image_data_type = T; - image_data_type data_out(width_, height_); + using image_type = T; + image_type data_out(width_, height_); if (nodata_) data_out.set(*nodata_); warp_image(data_out, data_in, prj_trans_, target_ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_); - image_data_rgba8 dst(width_, height_); + image_rgba8 dst(width_, height_); raster_colorizer_ptr colorizer = get(sym_, keys::colorizer); if (colorizer) colorizer->colorize(dst, data_out, nodata_, feature_); + premultiply_alpha(dst); composite_(dst, comp_op_, opacity_, start_x_, start_y_); } private: @@ -202,24 +205,14 @@ void render_raster_symbolizer(raster_symbolizer const& sym, composite_mode_e comp_op = get(sym, keys::comp_op, feature, common.vars_, src_over); double opacity = get(sym,keys::opacity,feature, common.vars_, 1.0); // only premultiply rgba8 images - if (source->data_.is()) + if (source->data_.is()) { - bool premultiply_source = !source->premultiplied_alpha_; auto is_premultiplied = get_optional(sym, keys::premultiplied, feature, common.vars_); - if (is_premultiplied) + if (is_premultiplied && *is_premultiplied) { - if (*is_premultiplied) premultiply_source = false; - else premultiply_source = true; - } - if (premultiply_source) - { - agg::rendering_buffer buffer(source->data_.getBytes(), - source->data_.width(), - source->data_.height(), - source->data_.width() * 4); - agg::pixfmt_rgba32 pixf(buffer); - pixf.premultiply(); + mapnik::set_premultiplied_alpha(source->data_, true); } + mapnik::premultiply_alpha(source->data_); } if (!prj_trans.equal()) @@ -227,7 +220,7 @@ void render_raster_symbolizer(raster_symbolizer const& sym, double offset_x = ext.minx() - start_x; double offset_y = ext.miny() - start_y; unsigned mesh_size = static_cast(get(sym,keys::mesh_size,feature, common.vars_, 16)); - detail::image_data_warp_dispatcher dispatcher(prj_trans, start_x, start_y, raster_width, raster_height, + detail::image_warp_dispatcher dispatcher(prj_trans, start_x, start_y, raster_width, raster_height, target_ext, source->ext_, offset_x, offset_y, mesh_size, scaling_method, source->get_filter_factor(), opacity, comp_op, sym, feature, composite, source->nodata()); @@ -243,14 +236,14 @@ void render_raster_symbolizer(raster_symbolizer const& sym, (std::abs(start_x) <= eps) && (std::abs(start_y) <= eps) ) { - if (source->data_.is()) + if (source->data_.is()) { - composite(util::get(source->data_), comp_op, opacity, start_x, start_y); + composite(util::get(source->data_), comp_op, opacity, start_x, start_y); } } else { - detail::image_data_dispatcher dispatcher(start_x, start_y, raster_width, raster_height, + detail::image_dispatcher dispatcher(start_x, start_y, raster_width, raster_height, image_ratio_x, image_ratio_y, scaling_method, source->get_filter_factor(), opacity, comp_op, sym, feature, composite, source->nodata()); diff --git a/include/mapnik/renderer_common/render_pattern.hpp b/include/mapnik/renderer_common/render_pattern.hpp index e694b5454..ffa3140c2 100644 --- a/include/mapnik/renderer_common/render_pattern.hpp +++ b/include/mapnik/renderer_common/render_pattern.hpp @@ -23,7 +23,7 @@ #ifndef MAPNIK_RENDER_PATTERN_HPP #define MAPNIK_RENDER_PATTERN_HPP -#include +#include #include // fwd decl @@ -35,12 +35,14 @@ namespace mapnik { // fwd decl struct rasterizer; -class marker; +struct marker_svg; -std::shared_ptr render_pattern(rasterizer & ras, - marker const& marker, - agg::trans_affine const& tr, - double opacity); +template +void render_pattern(rasterizer & ras, + marker_svg const& marker, + agg::trans_affine const& tr, + double opacity, + T & image); } // namespace mapnik diff --git a/include/mapnik/sse.hpp b/include/mapnik/sse.hpp new file mode 100644 index 000000000..d68684cd2 --- /dev/null +++ b/include/mapnik/sse.hpp @@ -0,0 +1,156 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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_SSE_HPP +#define MAPNIK_SSE_HPP + +#include +#include + +#define ROUND_DOWN(x, s) ((x) & ~((s)-1)) + +typedef union +{ + __m128i v; + int32_t i32[4]; + uint32_t u32[4]; + uint16_t u16[8]; + uint8_t u8[16]; +} m128_int; + +static inline __m128i +_mm_cmple_epu16 (__m128i x, __m128i y) +{ + // Returns 0xFFFF where x <= y: + return _mm_cmpeq_epi16(_mm_subs_epu16(x, y), _mm_setzero_si128()); +} + +static inline __m128i +_mm_cmple_epu8 (__m128i x, __m128i y) +{ + // Returns 0xFF where x <= y: + return _mm_cmpeq_epi8(_mm_min_epu8(x, y), x); +} + +static inline __m128i +_mm_cmpgt_epu16 (__m128i x, __m128i y) +{ + // Returns 0xFFFF where x > y: + return _mm_andnot_si128(_mm_cmpeq_epi16(x, y), _mm_cmple_epu16(y, x)); +} + +static inline __m128i +_mm_cmpgt_epu8 (__m128i x, __m128i y) +{ + // Returns 0xFF where x > y: + return _mm_andnot_si128( + _mm_cmpeq_epi8(x, y), + _mm_cmpeq_epi8(_mm_max_epu8(x, y), x) + ); +} + +static inline __m128i +_mm_cmplt_epu16 (__m128i x, __m128i y) +{ + // Returns 0xFFFF where x < y: + return _mm_cmpgt_epu16(y, x); +} + +static inline __m128i +_mm_cmplt_epu8 (__m128i x, __m128i y) +{ + // Returns 0xFF where x < y: + return _mm_cmpgt_epu8(y, x); +} + +static inline __m128i +_mm_cmpge_epu16 (__m128i x, __m128i y) +{ + // Returns 0xFFFF where x >= y: + return _mm_cmple_epu16(y, x); +} + +static inline __m128i +_mm_cmpge_epu8 (__m128i x, __m128i y) +{ + // Returns 0xFF where x >= y: + return _mm_cmple_epu8(y, x); +} + +// Its not often that you want to use this! +static inline __m128i +_mm_not_si128 (__m128i x) +{ + // Returns ~x, the bitwise complement of x: + return _mm_xor_si128(x, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())); +} + +static inline __m128i +_mm_absdiff_epu16 (__m128i x, __m128i y) +{ + // Calculate absolute difference: abs(x - y): + return _mm_or_si128(_mm_subs_epu16(x, y), _mm_subs_epu16(y, x)); +} + +static inline __m128i +_mm_absdiff_epu8 (__m128i x, __m128i y) +{ + // Calculate absolute difference: abs(x - y): + return _mm_or_si128(_mm_subs_epu8(x, y), _mm_subs_epu8(y, x)); +} + +static inline __m128i +_mm_div255_epu16 (__m128i x) +{ + // Divide 8 16-bit uints by 255: + // x := ((x + 1) + (x >> 8)) >> 8: + return _mm_srli_epi16(_mm_adds_epu16( + _mm_adds_epu16(x, _mm_set1_epi16(1)), + _mm_srli_epi16(x, 8)), 8); +} + +static __m128i +_mm_scale_epu8 (__m128i x, __m128i y) +{ + // Returns an "alpha blend" of x scaled by y/255; + // x := x * (y / 255) + // Reorder: x := (x * y) / 255 + + // Unpack x and y into 16-bit uints: + __m128i xlo = _mm_unpacklo_epi8(x, _mm_setzero_si128()); + __m128i ylo = _mm_unpacklo_epi8(y, _mm_setzero_si128()); + __m128i xhi = _mm_unpackhi_epi8(x, _mm_setzero_si128()); + __m128i yhi = _mm_unpackhi_epi8(y, _mm_setzero_si128()); + + // Multiply x with y, keeping the low 16 bits: + xlo = _mm_mullo_epi16(xlo, ylo); + xhi = _mm_mullo_epi16(xhi, yhi); + + // Divide by 255: + xlo = _mm_div255_epu16(xlo); + xhi = _mm_div255_epu16(xhi); + + // Repack the 16-bit uints to clamped 8-bit values: + return _mm_packus_epi16(xlo, xhi); +} + +#endif // MAPNIK_SSE_HPP diff --git a/include/mapnik/svg/output/svg_renderer.hpp b/include/mapnik/svg/output/svg_renderer.hpp index 43b3a77c2..fe4fc65e0 100644 --- a/include/mapnik/svg/output/svg_renderer.hpp +++ b/include/mapnik/svg/output/svg_renderer.hpp @@ -53,7 +53,7 @@ namespace mapnik { class feature_type_style; class label_collision_detector4; class layer; - class marker; + struct marker; class proj_transform; } diff --git a/include/mapnik/text/glyph_positions.hpp b/include/mapnik/text/glyph_positions.hpp index 86c0302ef..26c63b8d2 100644 --- a/include/mapnik/text/glyph_positions.hpp +++ b/include/mapnik/text/glyph_positions.hpp @@ -50,18 +50,20 @@ struct glyph_position struct marker_info { - marker_info() : marker(), transform() {} - marker_info(marker_ptr _marker, agg::trans_affine const& _transform) : + //marker_info() : marker(), transform() {} + marker_info(marker const& _marker, agg::trans_affine const& _transform) : marker(_marker), transform(_transform) {} - marker_ptr marker; + marker const& marker; agg::trans_affine transform; }; + using marker_info_ptr = std::shared_ptr; /** Stores positions of glphys. * * The actual glyphs and their format are stored in text_layout. */ + class glyph_positions { public: diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp index af60309d1..ab56a3282 100644 --- a/include/mapnik/tiff_io.hpp +++ b/include/mapnik/tiff_io.hpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include extern "C" @@ -35,12 +35,13 @@ extern "C" #define RealTIFFClose TIFFClose } +//std +#include + #define TIFF_WRITE_SCANLINE 0 #define TIFF_WRITE_STRIPPED 1 #define TIFF_WRITE_TILED 2 -#include - namespace mapnik { static inline tsize_t tiff_write_proc(thandle_t fd, tdata_t buf, tsize_t size) @@ -181,7 +182,7 @@ struct tiff_config struct tag_setter { - tag_setter(TIFF * output, tiff_config & config) + tag_setter(TIFF * output, tiff_config const& config) : output_(output), config_(config) {} @@ -192,15 +193,22 @@ struct tag_setter throw ImageWriterException("Could not write TIFF - unknown image type provided"); } - inline void operator() (image_data_rgba8 const&) const + inline void operator() (image_rgba8 const& data) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 4); - //uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; - uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; - TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); + if (data.get_premultiplied()) + { + uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA }; + TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); + } + else + { + uint16 extras[] = { EXTRASAMPLE_UNASSALPHA }; + TIFFSetField(output_, TIFFTAG_EXTRASAMPLES, 1, extras); + } if (config_.compression == COMPRESSION_DEFLATE || config_.compression == COMPRESSION_ADOBE_DEFLATE || config_.compression == COMPRESSION_LZW) @@ -209,7 +217,76 @@ struct tag_setter } } - inline void operator() (image_data_gray32f const&) const + inline void operator() (image_gray64 const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 64); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_gray64s const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 64); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_gray64f const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 64); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT); + } + } + inline void operator() (image_gray32 const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_gray32s const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_gray32f const&) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); @@ -222,7 +299,7 @@ struct tag_setter TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT); } } - inline void operator() (image_data_gray16 const&) const + inline void operator() (image_gray16 const&) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); @@ -236,7 +313,21 @@ struct tag_setter } } - inline void operator() (image_data_gray8 const&) const + inline void operator() (image_gray16s const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 16); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_gray8 const&) const { TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); @@ -250,7 +341,21 @@ struct tag_setter } } - inline void operator() (image_data_null const&) const + inline void operator() (image_gray8s const&) const + { + TIFFSetField(output_, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(output_, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(output_, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(output_, TIFFTAG_SAMPLESPERPIXEL, 1); + if (config_.compression == COMPRESSION_DEFLATE + || config_.compression == COMPRESSION_ADOBE_DEFLATE + || config_.compression == COMPRESSION_LZW) + { + TIFFSetField(output_, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL); + + } + } + inline void operator() (image_null const&) const { // Assume this would be null type throw ImageWriterException("Could not write TIFF - Null image provided"); @@ -258,10 +363,10 @@ struct tag_setter private: TIFF * output_; - tiff_config config_; + tiff_config const& config_; }; -void set_tiff_config(TIFF* output, tiff_config & config) +inline void set_tiff_config(TIFF* output, tiff_config const& config) { // Set some constant tiff information that doesn't vary based on type of data // or image size @@ -282,7 +387,7 @@ void set_tiff_config(TIFF* output, tiff_config & config) } template -void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) +void save_as_tiff(T1 & file, T2 const& image, tiff_config const& config) { using pixel_type = typename T2::pixel_type; @@ -312,7 +417,6 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) // Set tags that vary based on the type of data being provided. tag_setter set(output, config); set(image); - //util::apply_visitor(set, image); // Use specific types of writing methods. if (TIFF_WRITE_SCANLINE == config.method) @@ -339,9 +443,7 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, rows_per_strip); std::size_t strip_size = width * rows_per_strip; std::unique_ptr strip_buffer(new pixel_type[strip_size]); - int end_y=(height/rows_per_strip+1)*rows_per_strip; - - for (int y=0; y < end_y; y+=rows_per_strip) + for (int y=0; y < height; y+=rows_per_strip) { int ty1 = std::min(height, static_cast(y + rows_per_strip)) - y; int row = y; @@ -380,7 +482,7 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) TIFFSetField(output, TIFFTAG_TILELENGTH, tile_height); TIFFSetField(output, TIFFTAG_TILEDEPTH, 1); std::size_t tile_size = tile_width * tile_height; - std::unique_ptr image_data_out (new pixel_type[tile_size]); + std::unique_ptr image_out (new pixel_type[tile_size]); int end_y = (height / tile_height + 1) * tile_height; int end_x = (width / tile_width + 1) * tile_width; end_y = std::min(end_y, height); @@ -393,14 +495,14 @@ void save_as_tiff(T1 & file, T2 const& image, tiff_config & config) for (int x = 0; x < end_x; x += tile_width) { // Prefill the entire array with zeros. - std::fill(image_data_out.get(), image_data_out.get() + tile_size, 0); + std::fill(image_out.get(), image_out.get() + tile_size, 0); int tx1 = std::min(width, x + tile_width); int row = y; for (int ty = 0; ty < ty1; ++ty, ++row) { - std::copy(image.getRow(row, x), image.getRow(row, tx1), image_data_out.get() + ty * tile_width); + std::copy(image.getRow(row, x), image.getRow(row, tx1), image_out.get() + ty * tile_width); } - if (TIFFWriteEncodedTile(output, TIFFComputeTile(output, x, y, 0, 0), image_data_out.get(), tile_size * sizeof(pixel_type)) == -1) + if (TIFFWriteEncodedTile(output, TIFFComputeTile(output, x, y, 0, 0), image_out.get(), tile_size * sizeof(pixel_type)) == -1) { throw ImageWriterException("Could not write TIFF - TIFF Tile Write failed"); } diff --git a/include/mapnik/value_types.hpp b/include/mapnik/value_types.hpp index ffe021869..fdaa99ee4 100644 --- a/include/mapnik/value_types.hpp +++ b/include/mapnik/value_types.hpp @@ -25,6 +25,7 @@ // mapnik #include +#include // icu #include // for U_NAMESPACE_QUALIFIER @@ -42,9 +43,13 @@ namespace mapnik { #ifdef BIGINT //using value_integer = boost::long_long_type; -using value_integer = long long; +//using value_integer = long long; +using value_integer = std::int64_t; +using value_integer_pixel = gray64s_t; #else -using value_integer = int; +//using value_integer = int; +using value_integer = std::int32_t; +using value_integer_pixel = gray32s_t; #endif using value_double = double; diff --git a/include/mapnik/webp_io.hpp b/include/mapnik/webp_io.hpp index eecd65e70..6236d260c 100644 --- a/include/mapnik/webp_io.hpp +++ b/include/mapnik/webp_io.hpp @@ -24,7 +24,7 @@ #define MAPNIK_WEBP_IO_HPP // mapnik -#include +#include #include // webp @@ -73,14 +73,14 @@ std::string webp_encoding_error(WebPEncodingError error) } template -inline int import_image_data(T2 const& image, +inline int import_image(T2 const& im_in, WebPPicture & pic, bool alpha) { - image_data const& data = image.data(); - int stride = sizeof(typename T2::pixel_type) * image.width(); - if (data.width() == image.width() && - data.height() == image.height()) + image const& data = im_in.data(); + int stride = sizeof(typename T2::pixel_type) * im_in.width(); + if (data.width() == im_in.width() && + data.height() == im_in.height()) { if (alpha) { @@ -98,11 +98,11 @@ inline int import_image_data(T2 const& image, else { // need to copy: https://github.com/mapnik/mapnik/issues/2024 - image_data_rgba8 im(image.width(),image.height()); - for (unsigned y = 0; y < image.height(); ++y) + image_rgba8 im(im_in.width(),im_in.height()); + for (unsigned y = 0; y < im_in.height(); ++y) { - typename T2::pixel_type const * row_from = image.getRow(y); - image_data_rgba8::pixel_type * row_to = im.getRow(y); + typename T2::pixel_type const * row_from = im_in.getRow(y); + image_rgba8::pixel_type * row_to = im.getRow(y); std::copy(row_from, row_from + stride, row_to); } if (alpha) @@ -121,11 +121,11 @@ inline int import_image_data(T2 const& image, } template <> -inline int import_image_data(image_data_rgba8 const& im, +inline int import_image(image_rgba8 const& im, WebPPicture & pic, bool alpha) { - int stride = sizeof(image_data_rgba8::pixel_type) * im.width(); + int stride = sizeof(image_rgba8::pixel_type) * im.width(); if (alpha) { return WebPPictureImportRGBA(&pic, im.getBytes(), stride); @@ -187,10 +187,10 @@ void save_as_webp(T1& file, { // different approach for lossy since ImportYUVAFromRGBA is needed // to prepare WebPPicture and working with view pixels is not viable - ok = import_image_data(image,pic,alpha); + ok = import_image(image,pic,alpha); } #else - ok = import_image_data(image,pic,alpha); + ok = import_image(image,pic,alpha); #endif if (!ok) { diff --git a/include/mapnik/xml_attribute_cast.hpp b/include/mapnik/xml_attribute_cast.hpp index 6d2e4ae25..1a3cb98f2 100644 --- a/include/mapnik/xml_attribute_cast.hpp +++ b/include/mapnik/xml_attribute_cast.hpp @@ -25,6 +25,7 @@ //mapnik #include +#include #include #include #include @@ -87,14 +88,14 @@ struct do_xml_attribute_cast #ifdef BIGINT // specialization for long long template <> -struct do_xml_attribute_cast +struct do_xml_attribute_cast { - static inline boost::optional xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source) + static inline boost::optional xml_attribute_cast_impl(xml_tree const& /*tree*/, std::string const& source) { int result; if (mapnik::util::string2int(source, result)) - return boost::optional(result); - return boost::optional(); + return boost::optional(result); + return boost::optional(); } }; diff --git a/localize.sh b/localize.sh index 4f227e73c..1db825b48 100755 --- a/localize.sh +++ b/localize.sh @@ -10,4 +10,4 @@ export PYTHONPATH="${CURRENT_DIR}/bindings/python/":$PYTHONPATH export MAPNIK_FONT_DIRECTORY="${CURRENT_DIR}/fonts/dejavu-fonts-ttf-2.34/ttf/" export MAPNIK_INPUT_PLUGINS_DIRECTORY="${CURRENT_DIR}/plugins/input/" export PATH="${CURRENT_DIR}/utils/mapnik-config":${PATH} -export PATH="${CURRENT_DIR}/utils/nik2img":${PATH} \ No newline at end of file +export PATH="${CURRENT_DIR}/utils/nik2img":${PATH} diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 1e276cc2a..8ec66f27e 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -203,33 +203,99 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Reading band=" << band_; if (band_ > 0) // we are querying a single band { - mapnik::image_data_gray16 image(im_width, im_height); - image.set(std::numeric_limits::max()); + GDALRasterBand * band = dataset_.GetRasterBand(band_); if (band_ > nbands_) { std::ostringstream s; s << "GDAL Plugin: " << band_ << " is an invalid band, dataset only has " << nbands_ << "bands"; throw datasource_exception(s.str()); } - - GDALRasterBand * band = dataset_.GetRasterBand(band_); - raster_nodata = band->GetNoDataValue(&raster_has_nodata); - raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, - image.getData(), image.width(), image.height(), - GDT_Int16, 0, 0); - if (raster_io_error == CE_Failure) + GDALDataType band_type = band->GetRasterDataType(); + switch (band_type) { - throw datasource_exception(CPLGetLastErrorMsg()); + case GDT_Byte: + { + mapnik::image_gray8 image(im_width, im_height); + image.set(std::numeric_limits::max()); + raster_nodata = band->GetNoDataValue(&raster_has_nodata); + raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, + image.getData(), image.width(), image.height(), + GDT_Byte, 0, 0); + if (raster_io_error == CE_Failure) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } + mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); + // set nodata value to be used in raster colorizer + if (nodata_value_) raster->set_nodata(*nodata_value_); + else raster->set_nodata(raster_nodata); + feature->set_raster(raster); + break; + } + case GDT_Float64: + case GDT_Float32: + { + mapnik::image_gray32f image(im_width, im_height); + image.set(std::numeric_limits::max()); + raster_nodata = band->GetNoDataValue(&raster_has_nodata); + raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, + image.getData(), image.width(), image.height(), + GDT_Float32, 0, 0); + if (raster_io_error == CE_Failure) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } + mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); + // set nodata value to be used in raster colorizer + if (nodata_value_) raster->set_nodata(*nodata_value_); + else raster->set_nodata(raster_nodata); + feature->set_raster(raster); + break; + } + case GDT_UInt16: + { + mapnik::image_gray16 image(im_width, im_height); + image.set(std::numeric_limits::max()); + raster_nodata = band->GetNoDataValue(&raster_has_nodata); + raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, + image.getData(), image.width(), image.height(), + GDT_UInt16, 0, 0); + if (raster_io_error == CE_Failure) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } + mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); + // set nodata value to be used in raster colorizer + if (nodata_value_) raster->set_nodata(*nodata_value_); + else raster->set_nodata(raster_nodata); + feature->set_raster(raster); + break; + } + default: + case GDT_Int16: + { + mapnik::image_gray16s image(im_width, im_height); + image.set(std::numeric_limits::max()); + raster_nodata = band->GetNoDataValue(&raster_has_nodata); + raster_io_error = band->RasterIO(GF_Read, x_off, y_off, width, height, + image.getData(), image.width(), image.height(), + GDT_Int16, 0, 0); + if (raster_io_error == CE_Failure) + { + throw datasource_exception(CPLGetLastErrorMsg()); + } + mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); + // set nodata value to be used in raster colorizer + if (nodata_value_) raster->set_nodata(*nodata_value_); + else raster->set_nodata(raster_nodata); + feature->set_raster(raster); + break; + } } - mapnik::raster_ptr raster = std::make_shared(intersect, image, filter_factor); - // set nodata value to be used in raster colorizer - if (nodata_value_) raster->set_nodata(*nodata_value_); - else raster->set_nodata(raster_nodata); - feature->set_raster(raster); } else // working with all bands { - mapnik::image_data_rgba8 image(im_width, im_height); + mapnik::image_rgba8 image(im_width, im_height); image.set(std::numeric_limits::max()); for (int i = 0; i < nbands_; ++i) { diff --git a/plugins/input/pgraster/pgraster_featureset.cpp b/plugins/input/pgraster/pgraster_featureset.cpp index 497652561..20900cfe5 100644 --- a/plugins/input/pgraster/pgraster_featureset.cpp +++ b/plugins/input/pgraster/pgraster_featureset.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include // for int2net diff --git a/plugins/input/pgraster/pgraster_wkb_reader.cpp b/plugins/input/pgraster/pgraster_wkb_reader.cpp index d2e77048c..bea039e37 100644 --- a/plugins/input/pgraster/pgraster_wkb_reader.cpp +++ b/plugins/input/pgraster/pgraster_wkb_reader.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include // for box2d @@ -183,12 +183,7 @@ mapnik::raster_ptr read_data_band(mapnik::box2d const& bbox, uint16_t width, uint16_t height, bool hasnodata, T reader) { - mapnik::image_data_gray32f image(width, height); - //image.set(std::numeric_limits::max()); - // Start with plain white (ABGR or RGBA depending on endiannes) - // TODO: set to transparent instead? - image.set(0xffffffff); - + mapnik::image_gray32f image(width, height); float* data = image.getData(); double val; val = reader(); // nodata value, need to read anyway @@ -199,7 +194,7 @@ mapnik::raster_ptr read_data_band(mapnik::box2d const& bbox, data[off] = val; } } - mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0, true); + mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0); if ( hasnodata ) raster->set_nodata(val); return raster; } @@ -271,7 +266,7 @@ mapnik::raster_ptr read_grayscale_band(mapnik::box2d const& bbox, uint16_t width, uint16_t height, bool hasnodata, T reader) { - mapnik::image_data_rgba8 image(width,height); + mapnik::image_rgba8 image(width,height, true, true); // Start with plain white (ABGR or RGBA depending on endiannes) // TODO: set to transparent instead? image.set(0xffffffff); @@ -279,7 +274,7 @@ mapnik::raster_ptr read_grayscale_band(mapnik::box2d const& bbox, int val; uint8_t * data = image.getBytes(); - int ps = 4; // sizeof(image_data::pixel_type) + int ps = 4; // sizeof(image::pixel_type) int off; val = reader(); // nodata value, need to read anyway for (int y=0; y const& bbox, data[off+2] = val; } } - mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0, true); + mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0); if ( hasnodata ) raster->set_nodata(val); return raster; } @@ -352,9 +347,9 @@ mapnik::raster_ptr pgraster_wkb_reader::read_grayscale(mapnik::box2d con mapnik::raster_ptr pgraster_wkb_reader::read_rgba(mapnik::box2d const& bbox, uint16_t width, uint16_t height) { - mapnik::image_data_rgba8 image(width, height); + mapnik::image_rgba8 im(width, height, true, true); // Start with plain white (ABGR or RGBA depending on endiannes) - image.set(0xffffffff); + im.set(0xffffffff); uint8_t nodataval; for (int bn=0; bn const& b << " nodataval " << tmp << " != band 0 nodataval " << nodataval; } - int ps = 4; // sizeof(image_data::pixel_type) - uint8_t * image_data = image.getBytes(); + int ps = 4; // sizeof(image::pixel_type) + uint8_t * image_data = im.getBytes(); for (int y=0; y const& b } } } - mapnik::raster_ptr raster = std::make_shared(bbox, image, 1.0, true); + mapnik::raster_ptr raster = std::make_shared(bbox, im, 1.0); raster->set_nodata(0xffffffff); return raster; } diff --git a/plugins/input/raster/raster_featureset.cpp b/plugins/input/raster/raster_featureset.cpp index 6f5fa0376..4bf95571e 100644 --- a/plugins/input/raster/raster_featureset.cpp +++ b/plugins/input/raster/raster_featureset.cpp @@ -22,7 +22,7 @@ // mapnik #include -#include +#include #include #include #include @@ -43,7 +43,7 @@ using mapnik::query; using mapnik::image_reader; using mapnik::feature_ptr; -using mapnik::image_data_rgba8; +using mapnik::image_rgba8; using mapnik::raster; using mapnik::feature_factory; @@ -114,9 +114,8 @@ feature_ptr raster_featureset::next() rem.maxx() + x_off + width, rem.maxy() + y_off + height); intersect = t.backward(feature_raster_extent); - mapnik::image_data_any data = reader->read(x_off, y_off, width, height); + mapnik::image_any data = reader->read(x_off, y_off, width, height); mapnik::raster_ptr raster = std::make_shared(intersect, std::move(data), 1.0); - raster->premultiplied_alpha_ = reader->premultiplied_alpha(); feature->set_raster(raster); } } diff --git a/plugins/input/rasterlite/rasterlite_featureset.cpp b/plugins/input/rasterlite/rasterlite_featureset.cpp index 2e3c6bb40..c47294b8b 100644 --- a/plugins/input/rasterlite/rasterlite_featureset.cpp +++ b/plugins/input/rasterlite/rasterlite_featureset.cpp @@ -24,7 +24,7 @@ // mapnik #include -#include +#include #include #include #include @@ -114,10 +114,9 @@ feature_ptr rasterlite_featureset::get_feature(mapnik::query const& q) { if (size > 0) { - mapnik::image_data_rgba8 image(width,height); + mapnik::image_rgba8 image(width,height); unsigned char* raster_data = static_cast(raster); - unsigned char* image_data = image.getBytes(); - std::memcpy(image_data, raster_data, size); + std::memcpy(image.getBytes(), raster_data, size); feature->set_raster(std::make_shared(intersect, std::move(image), 1.0)); MAPNIK_LOG_DEBUG(rasterlite) << "rasterlite_featureset: Done"; } diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index d1ce80ca0..d988e9a2c 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +42,7 @@ #include #include #include +#include // agg #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" @@ -108,9 +108,52 @@ agg_renderer::agg_renderer(Map const& m, T0 & pixmap, std::shared_ptr setup(m); } +template +struct setup_agg_bg_visitor +{ + setup_agg_bg_visitor(buffer_type & pixmap, + renderer_common const& common, + composite_mode_e mode, + double opacity) + : pixmap_(pixmap), + common_(common), + mode_(mode), + opacity_(opacity) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const&) {} + + void operator() (marker_rgba8 const& marker) + { + mapnik::image_rgba8 const& bg_image = marker.get_data(); + int w = bg_image.width(); + int h = bg_image.height(); + if ( w > 0 && h > 0) + { + // repeat background-image both vertically and horizontally + unsigned x_steps = static_cast(std::ceil(common_.width_/double(w))); + unsigned y_steps = static_cast(std::ceil(common_.height_/double(h))); + for (unsigned x=0;x void agg_renderer::setup(Map const &m) { + mapnik::set_premultiplied_alpha(pixmap_, true); boost::optional const& bg = m.background(); if (bg) { @@ -118,11 +161,13 @@ void agg_renderer::setup(Map const &m) { mapnik::color bg_color = *bg; bg_color.premultiply(); - pixmap_.set_background(bg_color); + mapnik::fill(pixmap_, bg_color); } else { - pixmap_.set_background(*bg); + mapnik::color bg_color = *bg; + bg_color.set_premultiplied(true); + mapnik::fill(pixmap_,bg_color); } } @@ -130,26 +175,12 @@ void agg_renderer::setup(Map const &m) if (image_filename) { // NOTE: marker_cache returns premultiplied image, if needed - boost::optional bg_marker = mapnik::marker_cache::instance().find(*image_filename,true); - if (bg_marker && (*bg_marker)->is_bitmap()) - { - mapnik::image_ptr bg_image = *(*bg_marker)->get_bitmap_data(); - int w = bg_image->width(); - int h = bg_image->height(); - if ( w > 0 && h > 0) - { - // repeat background-image both vertically and horizontally - unsigned x_steps = static_cast(std::ceil(common_.width_/double(w))); - unsigned y_steps = static_cast(std::ceil(common_.height_/double(h))); - for (unsigned x=0;x visitor(pixmap_, + common_, + m.background_image_comp_op(), + m.background_image_opacity()); + util::apply_visitor(visitor, bg_marker); } MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Scale=" << m.scale(); } @@ -167,10 +198,7 @@ void agg_renderer::start_map_processing(Map const& map) template void agg_renderer::end_map_processing(Map const& ) { - - agg::rendering_buffer buf(pixmap_.raw_data(),common_.width_,common_.height_, common_.width_ * 4); - agg::pixfmt_rgba32_pre pixf(buf); - pixf.demultiply(); + mapnik::demultiply_alpha(pixmap_); MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: End map processing"; } @@ -239,7 +267,7 @@ void agg_renderer::start_style_processing(feature_type_style const& st) } else { - internal_buffer_->set_background(color(0,0,0,0)); // fill with transparent colour + mapnik::fill(*internal_buffer_, 0); // fill with transparent colour } } else @@ -250,12 +278,13 @@ void agg_renderer::start_style_processing(feature_type_style const& st) } else { - internal_buffer_->set_background(color(0,0,0,0)); // fill with transparent colour + mapnik::fill(*internal_buffer_, 0); // fill with transparent colour } common_.t_.set_offset(0); ras_ptr->clip_box(0,0,common_.width_,common_.height_); } current_buffer_ = internal_buffer_.get(); + set_premultiplied_alpha(*current_buffer_,true); } else { @@ -274,7 +303,7 @@ void agg_renderer::end_style_processing(feature_type_style const& st) if (st.image_filters().size() > 0) { blend_from = true; - mapnik::filter::filter_visitor visitor(*current_buffer_); + mapnik::filter::filter_visitor visitor(*current_buffer_); for (mapnik::filter::filter_type const& filter_tag : st.image_filters()) { util::apply_visitor(visitor, filter_tag); @@ -282,21 +311,21 @@ void agg_renderer::end_style_processing(feature_type_style const& st) } if (st.comp_op()) { - composite(pixmap_.data(), current_buffer_->data(), + composite(pixmap_, *current_buffer_, *st.comp_op(), st.get_opacity(), -common_.t_.offset(), - -common_.t_.offset(), false); + -common_.t_.offset()); } else if (blend_from || st.get_opacity() < 1.0) { - composite(pixmap_.data(), current_buffer_->data(), + composite(pixmap_, *current_buffer_, src_over, st.get_opacity(), -common_.t_.offset(), - -common_.t_.offset(), false); + -common_.t_.offset()); } } // apply any 'direct' image filters - mapnik::filter::filter_visitor visitor(pixmap_); + mapnik::filter::filter_visitor visitor(pixmap_); for (mapnik::filter::filter_type const& filter_tag : st.direct_image_filters()) { util::apply_visitor(visitor, filter_tag); @@ -304,87 +333,128 @@ void agg_renderer::end_style_processing(feature_type_style const& st) MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: End processing style"; } -template -void agg_renderer::render_marker(pixel_position const& pos, - marker const& marker, - agg::trans_affine const& tr, - double opacity, - composite_mode_e comp_op) +template +struct agg_render_marker_visitor { - using color_type = agg::rgba8; - using order_type = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender - using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - using renderer_type = agg::renderer_scanline_aa_solid; - using svg_attribute_type = agg::pod_bvector; + agg_render_marker_visitor(renderer_common & common, + buffer_type * current_buffer, + std::unique_ptr const& ras_ptr, + gamma_method_enum & gamma_method, + double & gamma, + pixel_position const& pos, + agg::trans_affine const& tr, + double opacity, + composite_mode_e comp_op) + : common_(common), + current_buffer_(current_buffer), + ras_ptr_(ras_ptr), + gamma_method_(gamma_method), + gamma_(gamma), + pos_(pos), + tr_(tr), + opacity_(opacity), + comp_op_(comp_op) {} - ras_ptr->reset(); - if (gamma_method_ != GAMMA_POWER || gamma_ != 1.0) - { - ras_ptr->gamma(agg::gamma_power()); - gamma_method_ = GAMMA_POWER; - gamma_ = 1.0; - } - agg::scanline_u8 sl; - agg::rendering_buffer buf(current_buffer_->raw_data(), - current_buffer_->width(), - current_buffer_->height(), - current_buffer_->width() * 4); - pixfmt_comp_type pixf(buf); - pixf.comp_op(static_cast(comp_op)); - renderer_base renb(pixf); + void operator() (marker_null const&) {} - if (marker.is_vector()) + void operator() (marker_svg const& marker) { - box2d const& bbox = (*marker.get_vector_data())->bounding_box(); + using color_type = agg::rgba8; + using order_type = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender + using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_scanline_aa_solid; + using svg_attribute_type = agg::pod_bvector; + + ras_ptr_->reset(); + if (gamma_method_ != GAMMA_POWER || gamma_ != 1.0) + { + ras_ptr_->gamma(agg::gamma_power()); + gamma_method_ = GAMMA_POWER; + gamma_ = 1.0; + } + agg::scanline_u8 sl; + agg::rendering_buffer buf(current_buffer_->getBytes(), + current_buffer_->width(), + current_buffer_->height(), + current_buffer_->getRowSize()); + pixfmt_comp_type pixf(buf); + pixf.comp_op(static_cast(comp_op_)); + renderer_base renb(pixf); + + box2d const& bbox = marker.get_data()->bounding_box(); coord c = bbox.center(); // center the svg marker on '0,0' agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); // apply symbol transformation to get to map space - mtx *= tr; + mtx *= tr_; mtx *= agg::trans_affine_scaling(common_.scale_factor_); // render the marker at the center of the marker box - mtx.translate(pos.x, pos.y); + mtx.translate(pos_.x, pos_.y); using namespace mapnik::svg; - vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + vertex_stl_adapter stl_storage(marker.get_data()->source()); svg_path_adapter svg_path(stl_storage); svg_renderer_agg svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); + marker.get_data()->attributes()); // https://github.com/mapnik/mapnik/issues/1316 // https://github.com/mapnik/mapnik/issues/1866 mtx.tx = std::floor(mtx.tx+.5); mtx.ty = std::floor(mtx.ty+.5); - svg_renderer.render(*ras_ptr, sl, renb, mtx, opacity, bbox); + svg_renderer.render(*ras_ptr_, sl, renb, mtx, opacity_, bbox); } - else + + void operator() (marker_rgba8 const& marker) { - double width = (*marker.get_bitmap_data())->width(); - double height = (*marker.get_bitmap_data())->height(); + using color_type = agg::rgba8; + using order_type = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; // comp blender + using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_scanline_aa_solid; + using svg_attribute_type = agg::pod_bvector; + + ras_ptr_->reset(); + if (gamma_method_ != GAMMA_POWER || gamma_ != 1.0) + { + ras_ptr_->gamma(agg::gamma_power()); + gamma_method_ = GAMMA_POWER; + gamma_ = 1.0; + } + agg::scanline_u8 sl; + agg::rendering_buffer buf(current_buffer_->getBytes(), + current_buffer_->width(), + current_buffer_->height(), + current_buffer_->getRowSize()); + pixfmt_comp_type pixf(buf); + pixf.comp_op(static_cast(comp_op_)); + renderer_base renb(pixf); + + double width = marker.width(); + double height = marker.height(); if (std::fabs(1.0 - common_.scale_factor_) < 0.001 - && (std::fabs(1.0 - tr.sx) < agg::affine_epsilon) - && (std::fabs(0.0 - tr.shy) < agg::affine_epsilon) - && (std::fabs(0.0 - tr.shx) < agg::affine_epsilon) - && (std::fabs(1.0 - tr.sy) < agg::affine_epsilon)) + && (std::fabs(1.0 - tr_.sx) < agg::affine_epsilon) + && (std::fabs(0.0 - tr_.shy) < agg::affine_epsilon) + && (std::fabs(0.0 - tr_.shx) < agg::affine_epsilon) + && (std::fabs(1.0 - tr_.sy) < agg::affine_epsilon)) { double cx = 0.5 * width; double cy = 0.5 * height; - composite(current_buffer_->data(), **marker.get_bitmap_data(), - comp_op, opacity, - std::floor(pos.x - cx + .5), - std::floor(pos.y - cy + .5), - false); + composite(*current_buffer_, marker.get_data(), + comp_op_, opacity_, + std::floor(pos_.x - cx + .5), + std::floor(pos_.y - cy + .5)); } else { double p[8]; - double x0 = pos.x - 0.5 * width; - double y0 = pos.y - 0.5 * height; + double x0 = pos_.x - 0.5 * width; + double y0 = pos_.y - 0.5 * height; p[0] = x0; p[1] = y0; p[2] = x0 + width; p[3] = y0; p[4] = x0 + width; p[5] = y0 + height; @@ -392,31 +462,31 @@ void agg_renderer::render_marker(pixel_position const& pos, agg::trans_affine marker_tr; - marker_tr *= agg::trans_affine_translation(-pos.x,-pos.y); - marker_tr *= tr; + marker_tr *= agg::trans_affine_translation(-pos_.x,-pos_.y); + marker_tr *= tr_; marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); - marker_tr *= agg::trans_affine_translation(pos.x,pos.y); + marker_tr *= agg::trans_affine_translation(pos_.x,pos_.y); marker_tr.transform(&p[0], &p[1]); marker_tr.transform(&p[2], &p[3]); marker_tr.transform(&p[4], &p[5]); marker_tr.transform(&p[6], &p[7]); - ras_ptr->move_to_d(p[0],p[1]); - ras_ptr->line_to_d(p[2],p[3]); - ras_ptr->line_to_d(p[4],p[5]); - ras_ptr->line_to_d(p[6],p[7]); + ras_ptr_->move_to_d(p[0],p[1]); + ras_ptr_->line_to_d(p[2],p[3]); + ras_ptr_->line_to_d(p[4],p[5]); + ras_ptr_->line_to_d(p[6],p[7]); agg::span_allocator sa; agg::image_filter_bilinear filter_kernel; agg::image_filter_lut filter(filter_kernel, false); - image_data_rgba8 const& src = **marker.get_bitmap_data(); + buffer_type const& src = marker.get_data(); agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), src.width(), src.height(), - src.width()*4); + src.getRowSize()); agg::pixfmt_rgba32_pre marker_pixf(marker_buf); using img_accessor_type = agg::image_accessor_clone; using interpolator_type = agg::span_interpolator_linear; @@ -431,10 +501,41 @@ void agg_renderer::render_marker(pixel_position const& pos, final_tr.ty = std::floor(final_tr.ty+.5); interpolator_type interpolator(final_tr); span_gen_type sg(ia, interpolator, filter); - renderer_type rp(renb,sa, sg, unsigned(opacity*255)); - agg::render_scanlines(*ras_ptr, sl, rp); + renderer_type rp(renb,sa, sg, unsigned(opacity_*255)); + agg::render_scanlines(*ras_ptr_, sl, rp); } } + + private: + renderer_common & common_; + buffer_type * current_buffer_; + std::unique_ptr const& ras_ptr_; + gamma_method_enum & gamma_method_; + double & gamma_; + pixel_position const& pos_; + agg::trans_affine const& tr_; + double opacity_; + composite_mode_e comp_op_; + +}; + +template +void agg_renderer::render_marker(pixel_position const& pos, + marker const& marker, + agg::trans_affine const& tr, + double opacity, + composite_mode_e comp_op) +{ + agg_render_marker_visitor visitor(common_, + current_buffer_, + ras_ptr, + gamma_method_, + gamma_, + pos, + tr, + opacity, + comp_op); + util::apply_visitor(visitor, marker); } template @@ -453,10 +554,10 @@ template void agg_renderer::debug_draw_box(box2d const& box, double x, double y, double angle) { - agg::rendering_buffer buf(current_buffer_->raw_data(), + agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), - current_buffer_->width() * 4); + current_buffer_->getRowSize()); debug_draw_box(buf, box, x, y, angle); } @@ -509,19 +610,19 @@ void agg_renderer::draw_geo_extent(box2d const& extent, mapnik::c unsigned rgba = color.rgba(); for (double x=x0; x; -template void agg_renderer::debug_draw_box( +template class agg_renderer; +template void agg_renderer::debug_draw_box( agg::rendering_buffer& buf, box2d const& box, double x, double y, double angle); -} +} // end ns diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index 492368aa1..3e0f88101 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -22,7 +22,7 @@ // mapnik #include -#include +#include #include #include #include @@ -58,7 +58,7 @@ void agg_renderer::process(building_symbolizer const& sym, using ren_base = agg::renderer_base; using renderer = agg::renderer_scanline_aa_solid; - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); agg::pixfmt_rgba32_pre pixf(buf); ren_base renb(pixf); @@ -115,8 +115,7 @@ void agg_renderer::process(building_symbolizer const& sym, }); } -template void agg_renderer::process(building_symbolizer const&, +template void agg_renderer::process(building_symbolizer const&, mapnik::feature_impl &, proj_transform const&); - } diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp index 45af47bee..bf4dde20d 100644 --- a/src/agg/process_debug_symbolizer.cpp +++ b/src/agg/process_debug_symbolizer.cpp @@ -23,13 +23,15 @@ // mapnik #include #include -#include +#include #include #include +#include namespace mapnik { -void draw_rect(image_32 &pixmap, box2d const& box) +template +void draw_rect(T &pixmap, box2d const& box) { int x0 = static_cast(box.minx()); int x1 = static_cast(box.maxx()); @@ -38,13 +40,13 @@ void draw_rect(image_32 &pixmap, box2d const& box) unsigned color1 = 0xff0000ff; for (int x=x0; x::process(debug_symbolizer const& sym, if (cmd == SEG_CLOSE) continue; prj_trans.backward(x,y,z); common_.t_.forward(&x,&y); - pixmap_.setPixel(x,y,0xff0000ff); - pixmap_.setPixel(x-1,y-1,0xff0000ff); - pixmap_.setPixel(x+1,y+1,0xff0000ff); - pixmap_.setPixel(x-1,y+1,0xff0000ff); - pixmap_.setPixel(x+1,y-1,0xff0000ff); + mapnik::set_pixel(pixmap_,x,y,0xff0000ff); + mapnik::set_pixel(pixmap_,x-1,y-1,0xff0000ff); + mapnik::set_pixel(pixmap_,x+1,y+1,0xff0000ff); + mapnik::set_pixel(pixmap_,x-1,y+1,0xff0000ff); + mapnik::set_pixel(pixmap_,x+1,y-1,0xff0000ff); } } } } -template void agg_renderer::process(debug_symbolizer const&, +template void agg_renderer::process(debug_symbolizer const&, mapnik::feature_impl &, proj_transform const&); } diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp index c57f7b32a..01893b655 100644 --- a/src/agg/process_dot_symbolizer.cpp +++ b/src/agg/process_dot_symbolizer.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -70,7 +70,7 @@ void agg_renderer::process(dot_symbolizer const& sym, double opacity = get(sym, keys::opacity, feature, common_.vars_, 1.0); color const& fill = get(sym, keys::fill, feature, common_.vars_, mapnik::color(128,128,128)); ras_ptr->reset(); - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(),current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(),current_buffer_->getRowSize()); using blender_type = agg::comp_op_adaptor_rgba_pre; using pixfmt_comp_type = agg::pixfmt_custom_blend_rgba; using renderer_base = agg::renderer_base; @@ -102,7 +102,7 @@ void agg_renderer::process(dot_symbolizer const& sym, } } -template void agg_renderer::process(dot_symbolizer const&, +template void agg_renderer::process(dot_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp index d8b2d3868..df930f2ac 100644 --- a/src/agg/process_group_symbolizer.cpp +++ b/src/agg/process_group_symbolizer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -48,9 +49,14 @@ namespace mapnik { * to render it, and the boxes themselves should already be * in the detector from the placement_finder. */ -struct thunk_renderer + +template +struct thunk_renderer; + +template <> +struct thunk_renderer { - using renderer_type = agg_renderer; + using renderer_type = agg_renderer; using buffer_type = renderer_type::buffer_type; using text_renderer_type = agg_text_renderer; @@ -75,7 +81,7 @@ struct thunk_renderer renderer_type, pixfmt_comp_type>; ras_ptr_->reset(); - buf_type render_buffer(buf_->raw_data(), buf_->width(), buf_->height(), buf_->width() * 4); + buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->getRowSize()); pixfmt_comp_type pixf(render_buffer); pixf.comp_op(static_cast(thunk.comp_op_)); renderer_base renb(pixf); @@ -96,7 +102,7 @@ struct thunk_renderer using renderer_base = agg::renderer_base; ras_ptr_->reset(); - buf_type render_buffer(buf_->raw_data(), buf_->width(), buf_->height(), buf_->width() * 4); + buf_type render_buffer(buf_->getBytes(), buf_->width(), buf_->height(), buf_->getRowSize()); pixfmt_comp_type pixf(render_buffer); pixf.comp_op(static_cast(thunk.comp_op_)); renderer_base renb(pixf); @@ -119,7 +125,7 @@ struct thunk_renderer if (glyphs->marker()) { ren_.render_marker(glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, thunk.opacity_, thunk.comp_op_); } @@ -130,7 +136,7 @@ struct thunk_renderer template void operator()(T const &) const { - // TODO: warning if unimplemented? + throw std::runtime_error("Rendering of this data type is not supported currently by the renderer"); } private: @@ -150,7 +156,7 @@ void agg_renderer::process(group_symbolizer const& sym, sym, feature, common_.vars_, prj_trans, clipping_extent(common_), common_, [&](render_thunk_list const& thunks, pixel_position const& render_offset) { - thunk_renderer ren(*this, ras_ptr, current_buffer_, common_, render_offset); + thunk_renderer ren(*this, ras_ptr, current_buffer_, common_, render_offset); for (render_thunk_ptr const& thunk : thunks) { util::apply_visitor(ren, *thunk); @@ -158,7 +164,7 @@ void agg_renderer::process(group_symbolizer const& sym, }); } -template void agg_renderer::process(group_symbolizer const&, +template void agg_renderer::process(group_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index fd2b21fbb..11e214518 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include #include #include @@ -52,100 +52,204 @@ namespace mapnik { +template +struct agg_renderer_process_visitor_l +{ + agg_renderer_process_visitor_l(renderer_common & common, + buffer_type & pixmap, + buffer_type * current_buffer, + std::unique_ptr const& ras_ptr, + line_pattern_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans) + : common_(common), + pixmap_(pixmap), + current_buffer_(current_buffer), + ras_ptr_(ras_ptr), + sym_(sym), + feature_(feature), + prj_trans_(prj_trans) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& marker) + { + using color = agg::rgba8; + using order = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; + using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; + using pattern_type = agg::line_image_pattern; + using pixfmt_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_outline_image; + using rasterizer_type = agg::rasterizer_outline_aa; + + value_double opacity = get(sym_, feature_, common_.vars_); + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; + image_rgba8 image(bbox_image.width(), bbox_image.height()); + render_pattern(*ras_ptr_, marker, image_tr, 1.0, image); + + value_bool clip = get(sym_, feature_, common_.vars_); + value_double offset = get(sym_, feature_, common_.vars_); + value_double simplify_tolerance = get(sym_, feature_, common_.vars_); + value_double smooth = get(sym_, feature_, common_.vars_); + + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); + pixfmt_type pixf(buf); + pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); + renderer_base ren_base(pixf); + agg::pattern_filter_bilinear_rgba8 filter; + + pattern_source source(image, opacity); + pattern_type pattern (filter,source); + renderer_type ren(ren_base, pattern); + rasterizer_type ras(ren); + + agg::trans_affine tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); + + box2d clip_box = clipping_extent(common_); + if (clip) + { + double padding = (double)(common_.query_extent_.width()/pixmap_.width()); + double half_stroke = marker.width()/2.0; + if (half_stroke > 1) + padding *= half_stroke; + if (std::fabs(offset) > 0) + padding *= std::fabs(offset) * 1.2; + padding *= common_.scale_factor_; + clip_box.pad(padding); + } + + vertex_converter + converter(clip_box,ras,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); + + if (clip) converter.set(); //optional clip (default: true) + converter.set(); //always transform + if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter + if (std::fabs(offset) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (smooth > 0.0) converter.set(); // optional smooth converter + + for (geometry_type const& geom : feature_.paths()) + { + if (geom.size() > 1) + { + vertex_adapter va(geom); + converter.apply(va); + } + } + } + + void operator() (marker_rgba8 const& marker) + { + using color = agg::rgba8; + using order = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; + using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; + using pattern_type = agg::line_image_pattern; + using pixfmt_type = agg::pixfmt_custom_blend_rgba; + using renderer_base = agg::renderer_base; + using renderer_type = agg::renderer_outline_image; + using rasterizer_type = agg::rasterizer_outline_aa; + + value_double opacity = get(sym_, feature_, common_.vars_); + mapnik::image_rgba8 const& image = marker.get_data(); + + value_bool clip = get(sym_, feature_, common_.vars_); + value_double offset = get(sym_, feature_, common_.vars_); + value_double simplify_tolerance = get(sym_, feature_, common_.vars_); + value_double smooth = get(sym_, feature_, common_.vars_); + + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); + pixfmt_type pixf(buf); + pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); + renderer_base ren_base(pixf); + agg::pattern_filter_bilinear_rgba8 filter; + + pattern_source source(image, opacity); + pattern_type pattern (filter,source); + renderer_type ren(ren_base, pattern); + rasterizer_type ras(ren); + + agg::trans_affine tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); + + box2d clip_box = clipping_extent(common_); + if (clip) + { + double padding = (double)(common_.query_extent_.width()/pixmap_.width()); + double half_stroke = marker.width()/2.0; + if (half_stroke > 1) + padding *= half_stroke; + if (std::fabs(offset) > 0) + padding *= std::fabs(offset) * 1.2; + padding *= common_.scale_factor_; + clip_box.pad(padding); + } + + vertex_converter + converter(clip_box,ras,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); + + if (clip) converter.set(); //optional clip (default: true) + converter.set(); //always transform + if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter + if (std::fabs(offset) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (smooth > 0.0) converter.set(); // optional smooth converter + + for (geometry_type const& geom : feature_.paths()) + { + if (geom.size() > 1) + { + vertex_adapter va(geom); + converter.apply(va); + } + } + } + + private: + renderer_common & common_; + buffer_type & pixmap_; + buffer_type * current_buffer_; + std::unique_ptr const& ras_ptr_; + line_pattern_symbolizer const& sym_; + mapnik::feature_impl & feature_; + proj_transform const& prj_trans_; +}; + template void agg_renderer::process(line_pattern_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - using color = agg::rgba8; - using order = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba_pre; - using pattern_filter_type = agg::pattern_filter_bilinear_rgba8; - using pattern_type = agg::line_image_pattern; - using pixfmt_type = agg::pixfmt_custom_blend_rgba; - using renderer_base = agg::renderer_base; - using renderer_type = agg::renderer_outline_image; - using rasterizer_type = agg::rasterizer_outline_aa; std::string filename = get(sym, feature, common_.vars_); if (filename.empty()) return; - boost::optional marker_ptr = marker_cache::instance().find(filename, true); - if (!marker_ptr || !(*marker_ptr)) return; - boost::optional pat; - // TODO - re-implement at renderer level like polygon_pattern symbolizer - value_double opacity = get(sym, feature, common_.vars_); - if ((*marker_ptr)->is_bitmap()) - { - pat = (*marker_ptr)->get_bitmap_data(); - } - else - { - agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); - } - - if (!pat) return; - - value_bool clip = get(sym, feature, common_.vars_); - value_double offset = get(sym, feature, common_.vars_); - value_double simplify_tolerance = get(sym, feature, common_.vars_); - value_double smooth = get(sym, feature, common_.vars_); - - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); - pixfmt_type pixf(buf); - pixf.comp_op(static_cast(get(sym, feature, common_.vars_))); - renderer_base ren_base(pixf); - agg::pattern_filter_bilinear_rgba8 filter; - - pattern_source source(*(*pat), opacity); - pattern_type pattern (filter,source); - renderer_type ren(ren_base, pattern); - rasterizer_type ras(ren); - - agg::trans_affine tr; - auto transform = get_optional(sym, keys::geometry_transform); - if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); - - box2d clip_box = clipping_extent(common_); - if (clip) - { - double padding = (double)(common_.query_extent_.width()/pixmap_.width()); - double half_stroke = (*marker_ptr)->width()/2.0; - if (half_stroke > 1) - padding *= half_stroke; - if (std::fabs(offset) > 0) - padding *= std::fabs(offset) * 1.2; - padding *= common_.scale_factor_; - clip_box.pad(padding); - } - - vertex_converter - converter(clip_box,ras,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - - if (clip) converter.set(); //optional clip (default: true) - converter.set(); //always transform - if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter - if (std::fabs(offset) > 0.0) converter.set(); // parallel offset - converter.set(); // optional affine transform - if (smooth > 0.0) converter.set(); // optional smooth converter - - for (geometry_type const& geom : feature.paths()) - { - if (geom.size() > 1) - { - vertex_adapter va(geom); - converter.apply(va); - } - } + mapnik::marker const & marker = marker_cache::instance().find(filename, true); + agg_renderer_process_visitor_l visitor(common_, + pixmap_, + current_buffer_, + ras_ptr, + sym, + feature, + prj_trans); + util::apply_visitor(visitor, marker); } -template void agg_renderer::process(line_pattern_symbolizer const&, +template void agg_renderer::process(line_pattern_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 8ebbf0737..34d405634 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -22,7 +22,7 @@ // mapnik #include -#include +#include #include #include #include @@ -109,7 +109,7 @@ void agg_renderer::process(line_symbolizer const& sym, gamma_ = gamma; } - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); using color_type = agg::rgba8; using order_type = agg::order_rgba; @@ -225,7 +225,7 @@ void agg_renderer::process(line_symbolizer const& sym, } -template void agg_renderer::process(line_symbolizer const&, +template void agg_renderer::process(line_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 31555bc6e..446cfa2ff 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -21,7 +21,6 @@ *****************************************************************************/ // mapnik -#include #include #include #include @@ -125,7 +124,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch; using renderer_base = agg::renderer_base; - raster_markers_rasterizer_dispatch(image_data_rgba8 & src, + raster_markers_rasterizer_dispatch(image_rgba8 const& src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -148,6 +147,8 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatchsrc_ provided that converts + // the destination pixel type required. render_raster_marker(renb_, ras_, this->src_, marker_tr, opacity, this->scale_factor_, snap_to_pixels_); } @@ -191,7 +192,7 @@ void agg_renderer::process(markers_symbolizer const& sym, gamma_ = gamma; } - buf_type render_buffer(current_buffer_->raw_data(), current_buffer_->width(), current_buffer_->height(), current_buffer_->width() * 4); + buf_type render_buffer(current_buffer_->getBytes(), current_buffer_->width(), current_buffer_->height(), current_buffer_->getRowSize()); box2d clip_box = clipping_extent(common_); auto renderer_context = std::tie(render_buffer,*ras_ptr,pixmap_); @@ -203,7 +204,7 @@ void agg_renderer::process(markers_symbolizer const& sym, sym, feature, prj_trans, common_, clip_box, renderer_context); } -template void agg_renderer::process(markers_symbolizer const&, +template void agg_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); } diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 950e9cb58..cabae6dc5 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,7 @@ void agg_renderer::process(point_symbolizer const& sym, }); } -template void agg_renderer::process(point_symbolizer const&, +template void agg_renderer::process(point_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 6e4211254..9a0622ca0 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -23,7 +23,6 @@ // mapnik #include #include -#include #include #include #include @@ -54,6 +53,254 @@ namespace mapnik { +template +struct agg_renderer_process_visitor_p +{ + agg_renderer_process_visitor_p(renderer_common & common, + buffer_type * current_buffer, + std::unique_ptr const& ras_ptr, + gamma_method_enum & gamma_method, + double & gamma, + polygon_pattern_symbolizer const& sym, + mapnik::feature_impl & feature, + proj_transform const& prj_trans) + : common_(common), + current_buffer_(current_buffer), + ras_ptr_(ras_ptr), + gamma_method_(gamma_method), + gamma_(gamma), + sym_(sym), + feature_(feature), + prj_trans_(prj_trans) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& marker) + { + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; + mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); + render_pattern(*ras_ptr_, marker, image_tr, 1.0, image); + + using clipped_geometry_type = agg::conv_clip_polygon; + using path_type = transform_path_adapter; + + agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), + current_buffer_->height(), current_buffer_->getRowSize()); + ras_ptr_->reset(); + value_double gamma = get(sym_, feature_, common_.vars_); + gamma_method_enum gamma_method = get(sym_, feature_, common_.vars_); + if (gamma != gamma_ || gamma_method != gamma_method_) + { + set_gamma_method(ras_ptr_, gamma, gamma_method); + gamma_method_ = gamma_method; + gamma_ = gamma; + } + + value_bool clip = get(sym_, feature_, common_.vars_); + value_double opacity = get(sym_, feature_, common_.vars_); + value_double simplify_tolerance = get(sym_, feature_, common_.vars_); + value_double smooth = get(sym_, feature_, common_.vars_); + + box2d clip_box = clipping_extent(common_); + + using color = agg::rgba8; + using order = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; + using pixfmt_type = agg::pixfmt_custom_blend_rgba; + + using wrap_x_type = agg::wrap_mode_repeat; + using wrap_y_type = agg::wrap_mode_repeat; + using img_source_type = agg::image_accessor_wrap; + + using span_gen_type = agg::span_pattern_rgba; + using ren_base = agg::renderer_base; + + using renderer_type = agg::renderer_scanline_aa_alpha, + span_gen_type>; + + pixfmt_type pixf(buf); + pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); + ren_base renb(pixf); + + unsigned w = image.width(); + unsigned h = image.height(); + agg::rendering_buffer pattern_rbuf((agg::int8u*)image.getBytes(),w,h,w*4); + agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); + img_source_type img_src(pixf_pattern); + + pattern_alignment_enum alignment = get(sym_, feature_, common_.vars_); + unsigned offset_x=0; + unsigned offset_y=0; + + if (alignment == LOCAL_ALIGNMENT) + { + double x0 = 0; + double y0 = 0; + if (feature_.num_geometries() > 0) + { + vertex_adapter va(feature_.get_geometry(0)); + clipped_geometry_type clipped(va); + clipped.clip_box(clip_box.minx(),clip_box.miny(),clip_box.maxx(),clip_box.maxy()); + path_type path(common_.t_,clipped,prj_trans_); + path.vertex(&x0,&y0); + } + offset_x = unsigned(current_buffer_->width() - x0); + offset_y = unsigned(current_buffer_->height() - y0); + } + + span_gen_type sg(img_src, offset_x, offset_y); + + agg::span_allocator sa; + renderer_type rp(renb,sa, sg, unsigned(opacity * 255)); + + agg::trans_affine tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); + + vertex_converter + converter(clip_box,*ras_ptr_,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); + + if (prj_trans_.equal() && clip) converter.set(); //optional clip (default: true) + converter.set(); //always transform + converter.set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter + if (smooth > 0.0) converter.set(); // optional smooth converter + + for ( geometry_type const& geom : feature_.paths()) + { + if (geom.size() > 2) + { + vertex_adapter va(geom); + converter.apply(va); + } + } + agg::scanline_u8 sl; + ras_ptr_->filling_rule(agg::fill_even_odd); + agg::render_scanlines(*ras_ptr_, sl, rp); + } + + void operator() (marker_rgba8 const& marker) + { + using clipped_geometry_type = agg::conv_clip_polygon; + using path_type = transform_path_adapter; + using color = agg::rgba8; + using order = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba_pre; + using pixfmt_type = agg::pixfmt_custom_blend_rgba; + + using wrap_x_type = agg::wrap_mode_repeat; + using wrap_y_type = agg::wrap_mode_repeat; + using img_source_type = agg::image_accessor_wrap; + + using span_gen_type = agg::span_pattern_rgba; + using ren_base = agg::renderer_base; + + using renderer_type = agg::renderer_scanline_aa_alpha, + span_gen_type>; + mapnik::image_rgba8 const& image = marker.get_data(); + + + agg::rendering_buffer buf(current_buffer_->getBytes(), current_buffer_->width(), + current_buffer_->height(), current_buffer_->getRowSize()); + ras_ptr_->reset(); + value_double gamma = get(sym_, feature_, common_.vars_); + gamma_method_enum gamma_method = get(sym_, feature_, common_.vars_); + if (gamma != gamma_ || gamma_method != gamma_method_) + { + set_gamma_method(ras_ptr_, gamma, gamma_method); + gamma_method_ = gamma_method; + gamma_ = gamma; + } + + value_bool clip = get(sym_, feature_, common_.vars_); + value_double opacity = get(sym_, feature_, common_.vars_); + value_double simplify_tolerance = get(sym_, feature_, common_.vars_); + value_double smooth = get(sym_, feature_, common_.vars_); + + box2d clip_box = clipping_extent(common_); + + + pixfmt_type pixf(buf); + pixf.comp_op(static_cast(get(sym_, feature_, common_.vars_))); + ren_base renb(pixf); + + unsigned w = image.width(); + unsigned h = image.height(); + agg::rendering_buffer pattern_rbuf((agg::int8u*)image.getBytes(),w,h,w*4); + agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); + img_source_type img_src(pixf_pattern); + + pattern_alignment_enum alignment = get(sym_, feature_, common_.vars_); + unsigned offset_x=0; + unsigned offset_y=0; + + if (alignment == LOCAL_ALIGNMENT) + { + double x0 = 0; + double y0 = 0; + if (feature_.num_geometries() > 0) + { + vertex_adapter va(feature_.get_geometry(0)); + clipped_geometry_type clipped(va); + clipped.clip_box(clip_box.minx(),clip_box.miny(),clip_box.maxx(),clip_box.maxy()); + path_type path(common_.t_,clipped,prj_trans_); + path.vertex(&x0,&y0); + } + offset_x = unsigned(current_buffer_->width() - x0); + offset_y = unsigned(current_buffer_->height() - y0); + } + + span_gen_type sg(img_src, offset_x, offset_y); + + agg::span_allocator sa; + renderer_type rp(renb,sa, sg, unsigned(opacity * 255)); + + agg::trans_affine tr; + auto transform = get_optional(sym_, keys::geometry_transform); + if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_); + + vertex_converter + converter(clip_box,*ras_ptr_,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); + + if (prj_trans_.equal() && clip) converter.set(); //optional clip (default: true) + converter.set(); //always transform + converter.set(); // optional affine transform + if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter + if (smooth > 0.0) converter.set(); // optional smooth converter + + for ( geometry_type const& geom : feature_.paths()) + { + if (geom.size() > 2) + { + vertex_adapter va(geom); + converter.apply(va); + } + } + agg::scanline_u8 sl; + ras_ptr_->filling_rule(agg::fill_even_odd); + agg::render_scanlines(*ras_ptr_, sl, rp); + } + + private: + renderer_common & common_; + buffer_type * current_buffer_; + std::unique_ptr const& ras_ptr_; + gamma_method_enum & gamma_method_; + double & gamma_; + polygon_pattern_symbolizer const& sym_; + mapnik::feature_impl & feature_; + proj_transform const& prj_trans_; +}; + template void agg_renderer::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, @@ -61,128 +308,20 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, { std::string filename = get(sym, feature, common_.vars_); if (filename.empty()) return; - boost::optional marker_ptr = marker_cache::instance().find(filename, true); - if (!marker_ptr || !(*marker_ptr)) return; - - boost::optional pat; - - if ((*marker_ptr)->is_bitmap()) - { - pat = (*marker_ptr)->get_bitmap_data(); - } - else - { - agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - pat = render_pattern(*ras_ptr, **marker_ptr, image_tr, 1.0); - } - - if (!pat) return; - - using clipped_geometry_type = agg::conv_clip_polygon; - using path_type = transform_path_adapter; - - agg::rendering_buffer buf(current_buffer_->raw_data(), current_buffer_->width(), - current_buffer_->height(), current_buffer_->width() * 4); - ras_ptr->reset(); - value_double gamma = get(sym, feature, common_.vars_); - gamma_method_enum gamma_method = get(sym, feature, common_.vars_); - if (gamma != gamma_ || gamma_method != gamma_method_) - { - set_gamma_method(ras_ptr, gamma, gamma_method); - gamma_method_ = gamma_method; - gamma_ = gamma; - } - - value_bool clip = get(sym, feature, common_.vars_); - value_double opacity = get(sym, feature, common_.vars_); - value_double simplify_tolerance = get(sym, feature, common_.vars_); - value_double smooth = get(sym, feature, common_.vars_); - - box2d clip_box = clipping_extent(common_); - - using color = agg::rgba8; - using order = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba_pre; - using pixfmt_type = agg::pixfmt_custom_blend_rgba; - - using wrap_x_type = agg::wrap_mode_repeat; - using wrap_y_type = agg::wrap_mode_repeat; - using img_source_type = agg::image_accessor_wrap; - - using span_gen_type = agg::span_pattern_rgba; - using ren_base = agg::renderer_base; - - using renderer_type = agg::renderer_scanline_aa_alpha, - span_gen_type>; - - pixfmt_type pixf(buf); - pixf.comp_op(static_cast(get(sym, feature, common_.vars_))); - ren_base renb(pixf); - - unsigned w=(*pat)->width(); - unsigned h=(*pat)->height(); - agg::rendering_buffer pattern_rbuf((agg::int8u*)(*pat)->getBytes(),w,h,w*4); - agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf); - img_source_type img_src(pixf_pattern); - - pattern_alignment_enum alignment = get(sym, feature, common_.vars_); - unsigned offset_x=0; - unsigned offset_y=0; - - if (alignment == LOCAL_ALIGNMENT) - { - double x0 = 0; - double y0 = 0; - if (feature.num_geometries() > 0) - { - vertex_adapter va(feature.get_geometry(0)); - clipped_geometry_type clipped(va); - clipped.clip_box(clip_box.minx(),clip_box.miny(),clip_box.maxx(),clip_box.maxy()); - path_type path(common_.t_,clipped,prj_trans); - path.vertex(&x0,&y0); - } - offset_x = unsigned(current_buffer_->width() - x0); - offset_y = unsigned(current_buffer_->height() - y0); - } - - span_gen_type sg(img_src, offset_x, offset_y); - - agg::span_allocator sa; - renderer_type rp(renb,sa, sg, unsigned(opacity * 255)); - - agg::trans_affine tr; - auto transform = get_optional(sym, keys::geometry_transform); - if (transform) evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_); - - vertex_converter - converter(clip_box,*ras_ptr,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - - if (prj_trans.equal() && clip) converter.set(); //optional clip (default: true) - converter.set(); //always transform - converter.set(); // optional affine transform - if (simplify_tolerance > 0.0) converter.set(); // optional simplify converter - if (smooth > 0.0) converter.set(); // optional smooth converter - - for ( geometry_type const& geom : feature.paths()) - { - if (geom.size() > 2) - { - vertex_adapter va(geom); - converter.apply(va); - } - } - agg::scanline_u8 sl; - ras_ptr->filling_rule(agg::fill_even_odd); - agg::render_scanlines(*ras_ptr, sl, rp); + mapnik::marker const& marker = marker_cache::instance().find(filename, true); + agg_renderer_process_visitor_p visitor(common_, + current_buffer_, + ras_ptr, + gamma_method_, + gamma_, + sym, + feature, + prj_trans); + util::apply_visitor(visitor, marker); } -template void agg_renderer::process(polygon_pattern_symbolizer const&, +template void agg_renderer::process(polygon_pattern_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index d02ead68c..af53dff06 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -26,7 +26,6 @@ // mapnik #include #include -#include #include #include #include @@ -62,7 +61,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, } box2d clip_box = clipping_extent(common_); - agg::rendering_buffer buf(current_buffer_->raw_data(),current_buffer_->width(),current_buffer_->height(), current_buffer_->width() * 4); + agg::rendering_buffer buf(current_buffer_->getBytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->getRowSize()); render_polygon_symbolizer( sym, feature, prj_trans, common_, clip_box, *ras_ptr, @@ -88,7 +87,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, }); } -template void agg_renderer::process(polygon_symbolizer const&, +template void agg_renderer::process(polygon_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index 4af75bbd6..7d5cd4b93 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -25,11 +25,10 @@ #include #include #include -#include #include #include #include -#include +#include #include #include #include @@ -52,15 +51,15 @@ void agg_renderer::process(raster_symbolizer const& sym, { render_raster_symbolizer( sym, feature, prj_trans, common_, - [&](image_data_rgba8 & target, composite_mode_e comp_op, double opacity, + [&](image_rgba8 & target, composite_mode_e comp_op, double opacity, int start_x, int start_y) { - composite(current_buffer_->data(), target, - comp_op, opacity, start_x, start_y, false); + composite(*current_buffer_, target, + comp_op, opacity, start_x, start_y); } ); } -template void agg_renderer::process(raster_symbolizer const&, +template void agg_renderer::process(raster_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index cd039d9b7..008b427c6 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -23,7 +23,6 @@ // mapnik #include #include -#include #include #include #include @@ -65,7 +64,7 @@ void agg_renderer::process(shield_symbolizer const& sym, { if (glyphs->marker()) render_marker(glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, opacity, comp_op); ren.render(*glyphs); @@ -73,7 +72,7 @@ void agg_renderer::process(shield_symbolizer const& sym, } -template void agg_renderer::process(shield_symbolizer const&, +template void agg_renderer::process(shield_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index b7ed299d4..c697d0521 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include #include #include @@ -75,7 +75,7 @@ void agg_renderer::process(text_symbolizer const& sym, } } -template void agg_renderer::process(text_symbolizer const&, +template void agg_renderer::process(text_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/build.py b/src/build.py index dd2ee353d..fca14e4b2 100644 --- a/src/build.py +++ b/src/build.py @@ -152,6 +152,7 @@ source = Split( miniz_png.cpp color.cpp conversions.cpp + image_copy.cpp image_compositing.cpp image_scaling.cpp box2d.cpp @@ -170,10 +171,14 @@ source = Split( font_set.cpp function_call.cpp gradient.cpp - graphics.cpp parse_path.cpp image_reader.cpp + cairo_io.cpp image_util.cpp + image_util_jpeg.cpp + image_util_png.cpp + image_util_tiff.cpp + image_util_webp.cpp layer.cpp map.cpp load_map.cpp diff --git a/src/cairo/cairo_context.cpp b/src/cairo/cairo_context.cpp index 8f2c60a61..fe35c3a9f 100644 --- a/src/cairo/cairo_context.cpp +++ b/src/cairo/cairo_context.cpp @@ -337,7 +337,7 @@ void cairo_context::set_gradient(cairo_gradient const& pattern, const box2d::cairo_renderer(Map const& m, template cairo_renderer::~cairo_renderer() {} +struct setup_marker_visitor +{ + setup_marker_visitor(cairo_context & context, renderer_common const& common) + : context_(context), common_(common) {} + + void operator() (marker_null const &) {} + void operator() (marker_svg const &) {} + + void operator() (marker_rgba8 const& marker) + { + mapnik::image_rgba8 const& bg_image = marker.get_data(); + int w = bg_image.width(); + int h = bg_image.height(); + if ( w > 0 && h > 0) + { + // repeat background-image both vertically and horizontally + unsigned x_steps = unsigned(std::ceil(common_.width_/double(w))); + unsigned y_steps = unsigned(std::ceil(common_.height_/double(h))); + for (unsigned x=0;x void cairo_renderer::setup(Map const& map) { @@ -113,29 +149,8 @@ void cairo_renderer::setup(Map const& map) if (image_filename) { // NOTE: marker_cache returns premultiplied image, if needed - boost::optional bg_marker = mapnik::marker_cache::instance().find(*image_filename,true); - if (bg_marker && (*bg_marker)->is_bitmap()) - { - mapnik::image_ptr bg_image = *(*bg_marker)->get_bitmap_data(); - int w = bg_image->width(); - int h = bg_image->height(); - if ( w > 0 && h > 0) - { - // repeat background-image both vertically and horizontally - unsigned x_steps = unsigned(std::ceil(common_.width_/double(w))); - unsigned y_steps = unsigned(std::ceil(common_.height_/double(h))); - for (unsigned x=0;x bbox = vmarker->bounding_box(); + agg::trans_affine marker_tr = tr_; + if (recenter_) + { + coord c = bbox.center(); + marker_tr = agg::trans_affine_translation(-c.x,-c.y); + marker_tr *= tr_; + } + marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); + agg::pod_bvector const & attributes = vmarker->attributes(); + svg::vertex_stl_adapter stl_storage(vmarker->source()); + svg::svg_path_adapter svg_path(stl_storage); + marker_tr.translate(pos_.x, pos_.y); + render_vector_marker(context_, svg_path, attributes, bbox, marker_tr, opacity_); + } + } + + void operator() (marker_rgba8 const& marker) + { + double width = marker.get_data().width(); + double height = marker.get_data().height(); + double cx = 0.5 * width; + double cy = 0.5 * height; + agg::trans_affine marker_tr; + marker_tr *= agg::trans_affine_translation(-cx,-cy); + marker_tr *= tr_; + marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); + marker_tr *= agg::trans_affine_translation(pos_.x,pos_.y); + context_.add_image(marker_tr, marker.get_data(), opacity_); + } + + private: + cairo_context & context_; + renderer_common const& common_; + pixel_position const& pos_; + agg::trans_affine const& tr_; + double opacity_; + bool recenter_; +}; + template void cairo_renderer::render_marker(pixel_position const& pos, marker const& marker, @@ -196,40 +273,13 @@ void cairo_renderer::render_marker(pixel_position const& pos, { cairo_save_restore guard(context_); - if (marker.is_vector()) - { - mapnik::svg_path_ptr vmarker = *marker.get_vector_data(); - if (vmarker) - { - box2d bbox = vmarker->bounding_box(); - agg::trans_affine marker_tr = tr; - if (recenter) - { - coord c = bbox.center(); - marker_tr = agg::trans_affine_translation(-c.x,-c.y); - marker_tr *= tr; - } - marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); - agg::pod_bvector const & attributes = vmarker->attributes(); - svg::vertex_stl_adapter stl_storage(vmarker->source()); - svg::svg_path_adapter svg_path(stl_storage); - marker_tr.translate(pos.x, pos.y); - render_vector_marker(context_, svg_path, attributes, bbox, marker_tr, opacity); - } - } - else if (marker.is_bitmap()) - { - double width = (*marker.get_bitmap_data())->width(); - double height = (*marker.get_bitmap_data())->height(); - double cx = 0.5 * width; - double cy = 0.5 * height; - agg::trans_affine marker_tr; - marker_tr *= agg::trans_affine_translation(-cx,-cy); - marker_tr *= tr; - marker_tr *= agg::trans_affine_scaling(common_.scale_factor_); - marker_tr *= agg::trans_affine_translation(pos.x,pos.y); - context_.add_image(marker_tr, **marker.get_bitmap_data(), opacity); - } + cairo_render_marker_visitor visitor(context_, + common_, + pos, + tr, + opacity, + recenter); + util::apply_visitor(visitor, marker); } template class cairo_renderer; diff --git a/src/cairo/process_group_symbolizer.cpp b/src/cairo/process_group_symbolizer.cpp index 37ba4c789..1e46a2028 100644 --- a/src/cairo/process_group_symbolizer.cpp +++ b/src/cairo/process_group_symbolizer.cpp @@ -77,7 +77,7 @@ struct thunk_renderer thunk.opacity_); } - void operator()(raster_marker_render_thunk const &thunk) const + void operator()(raster_marker_render_thunk const& thunk) const { cairo_save_restore guard(context_); context_.set_operator(thunk.comp_op_); @@ -100,7 +100,7 @@ struct thunk_renderer if (glyphs->marker()) { ren_.render_marker(glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, thunk.opacity_, thunk.comp_op_); } @@ -111,7 +111,7 @@ struct thunk_renderer template void operator()(T0 const &) const { - // TODO: warning if unimplemented? + throw std::runtime_error("Rendering of this type is not supported by the cairo renderer."); } private: diff --git a/src/cairo/process_line_pattern_symbolizer.cpp b/src/cairo/process_line_pattern_symbolizer.cpp index 46c72cd77..7048ff812 100644 --- a/src/cairo/process_line_pattern_symbolizer.cpp +++ b/src/cairo/process_line_pattern_symbolizer.cpp @@ -36,6 +36,53 @@ namespace mapnik { +struct cairo_renderer_process_visitor_l +{ + cairo_renderer_process_visitor_l(renderer_common const& common, + line_pattern_symbolizer const& sym, + mapnik::feature_impl & feature, + unsigned & width, + unsigned & height) + : common_(common), + sym_(sym), + feature_(feature), + width_(width), + height_(height) {} + + std::shared_ptr operator() (mapnik::marker_null const&) + { + throw std::runtime_error("This should not have been reached."); + } + + std::shared_ptr operator() (mapnik::marker_svg const& marker) + { + double opacity = get(sym_, feature_, common_.vars_); + mapnik::rasterizer ras; + agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); + auto image_transform = get_optional(sym_, keys::image_transform); + if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform); + mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr; + mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); + render_pattern(ras, marker, image_tr, 1.0, image); + width_ = image.width(); + height_ = image.height(); + return std::make_shared(image, opacity); + } + + std::shared_ptr operator() (mapnik::marker_rgba8 const& marker) + { + double opacity = get(sym_, feature_, common_.vars_); + return std::make_shared(marker.get_data(), opacity); + } + + private: + renderer_common const& common_; + line_pattern_symbolizer const& sym_; + mapnik::feature_impl & feature_; + unsigned & width_; + unsigned & height_; +}; + template void cairo_renderer::process(line_pattern_symbolizer const& sym, mapnik::feature_impl & feature, @@ -48,39 +95,29 @@ void cairo_renderer::process(line_pattern_symbolizer const& sym, value_double simplify_tolerance = get(sym, feature, common_.vars_); value_double smooth = get(sym, feature, common_.vars_); - boost::optional marker; - if ( !filename.empty() ) + if (filename.empty()) { - marker = marker_cache::instance().find(filename, true); + return; } - if (!marker || !(*marker)) return; - unsigned width = (*marker)->width(); - unsigned height = (*marker)->height(); + mapnik::marker const& marker = marker_cache::instance().find(filename, true); + + if (marker.is()) return; + + unsigned width = marker.width(); + unsigned height = marker.height(); cairo_save_restore guard(context_); context_.set_operator(comp_op); - std::shared_ptr pattern; - image_ptr image = nullptr; // TODO - re-implement at renderer level like polygon_pattern symbolizer - double opacity = get(sym, feature, common_.vars_); - if ((*marker)->is_bitmap()) - { - pattern = std::make_unique(**((*marker)->get_bitmap_data()), opacity); - context_.set_line_width(height); - } - else - { - mapnik::rasterizer ras; - agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_); - auto image_transform = get_optional(sym, keys::image_transform); - if (image_transform) evaluate_transform(image_tr, feature, common_.vars_, *image_transform); - image = render_pattern(ras, **marker, image_tr, 1.0); - pattern = std::make_unique(*image, opacity); - width = image->width(); - height = image->height(); - context_.set_line_width(height); - } + cairo_renderer_process_visitor_l visit(common_, + sym, + feature, + width, + height); + std::shared_ptr pattern = util::apply_visitor(visit, marker); + + context_.set_line_width(height); pattern->set_extend(CAIRO_EXTEND_REPEAT); pattern->set_filter(CAIRO_FILTER_BILINEAR); diff --git a/src/cairo/process_markers_symbolizer.cpp b/src/cairo/process_markers_symbolizer.cpp index d741c64f1..3cfb39496 100644 --- a/src/cairo/process_markers_symbolizer.cpp +++ b/src/cairo/process_markers_symbolizer.cpp @@ -86,7 +86,7 @@ private: template struct raster_markers_dispatch_cairo : public raster_markers_dispatch { - raster_markers_dispatch_cairo(mapnik::image_data_rgba8 & src, + raster_markers_dispatch_cairo(image_rgba8 const& src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, diff --git a/src/cairo/process_polygon_pattern_symbolizer.cpp b/src/cairo/process_polygon_pattern_symbolizer.cpp index b20d6bd99..f074260eb 100644 --- a/src/cairo/process_polygon_pattern_symbolizer.cpp +++ b/src/cairo/process_polygon_pattern_symbolizer.cpp @@ -37,6 +37,49 @@ namespace mapnik { +struct cairo_renderer_process_visitor_p +{ + cairo_renderer_process_visitor_p(cairo_context & context, + agg::trans_affine & image_tr, + unsigned offset_x, + unsigned offset_y, + float opacity) + : context_(context), + image_tr_(image_tr), + offset_x_(offset_x), + offset_y_(offset_y), + opacity_(opacity) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& marker) + { + mapnik::rasterizer ras; + mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr_; + mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); + render_pattern(ras, marker, image_tr_, 1.0, image); + cairo_pattern pattern(image, opacity_); + pattern.set_extend(CAIRO_EXTEND_REPEAT); + pattern.set_origin(offset_x_, offset_y_); + context_.set_pattern(pattern); + } + + void operator() (marker_rgba8 const& marker) + { + cairo_pattern pattern(marker.get_data(), opacity_); + pattern.set_extend(CAIRO_EXTEND_REPEAT); + pattern.set_origin(offset_x_, offset_y_); + context_.set_pattern(pattern); + } + + private: + cairo_context & context_; + agg::trans_affine & image_tr_; + unsigned offset_x_; + unsigned offset_y_; + float opacity_; +}; + template void cairo_renderer::process(polygon_pattern_symbolizer const& sym, mapnik::feature_impl & feature, @@ -55,8 +98,8 @@ void cairo_renderer::process(polygon_pattern_symbolizer const& sym, cairo_save_restore guard(context_); context_.set_operator(comp_op); - boost::optional marker = mapnik::marker_cache::instance().find(filename,true); - if (!marker || !(*marker)) return; + mapnik::marker const& marker = mapnik::marker_cache::instance().find(filename,true); + if (marker.is()) return; unsigned offset_x=0; unsigned offset_y=0; @@ -82,22 +125,7 @@ void cairo_renderer::process(polygon_pattern_symbolizer const& sym, offset_y = std::abs(clip_box.height() - y0); } - if ((*marker)->is_bitmap()) - { - cairo_pattern pattern(**((*marker)->get_bitmap_data()), opacity); - pattern.set_extend(CAIRO_EXTEND_REPEAT); - pattern.set_origin(offset_x, offset_y); - context_.set_pattern(pattern); - } - else - { - mapnik::rasterizer ras; - image_ptr image = render_pattern(ras, **marker, image_tr, 1.0); // - cairo_pattern pattern(*image, opacity); - pattern.set_extend(CAIRO_EXTEND_REPEAT); - pattern.set_origin(offset_x, offset_y); - context_.set_pattern(pattern); - } + util::apply_visitor(cairo_renderer_process_visitor_p(context_, image_tr, offset_x, offset_y, opacity), marker); agg::trans_affine tr; auto geom_transform = get_optional(sym, keys::geometry_transform); diff --git a/src/cairo/process_raster_symbolizer.cpp b/src/cairo/process_raster_symbolizer.cpp index 36daee737..7915ebbdd 100644 --- a/src/cairo/process_raster_symbolizer.cpp +++ b/src/cairo/process_raster_symbolizer.cpp @@ -43,7 +43,7 @@ void cairo_renderer::process(raster_symbolizer const& sym, cairo_save_restore guard(context_); render_raster_symbolizer( sym, feature, prj_trans, common_, - [&](image_data_rgba8 &target, composite_mode_e comp_op, double opacity, + [&](image_rgba8 &target, composite_mode_e comp_op, double opacity, int start_x, int start_y) { context_.set_operator(comp_op); context_.add_image(start_x, start_y, target, opacity); diff --git a/src/cairo/process_text_symbolizer.cpp b/src/cairo/process_text_symbolizer.cpp index 365e5f662..061e6b7c2 100644 --- a/src/cairo/process_text_symbolizer.cpp +++ b/src/cairo/process_text_symbolizer.cpp @@ -60,7 +60,7 @@ void cairo_renderer::process(shield_symbolizer const& sym, if (glyphs->marker()) { pixel_position pos = glyphs->marker_pos(); render_marker(pos, - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, opacity); } diff --git a/src/cairo_io.cpp b/src/cairo_io.cpp new file mode 100644 index 000000000..0eefa2e89 --- /dev/null +++ b/src/cairo_io.cpp @@ -0,0 +1,131 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +#include + +#ifdef HAVE_CAIRO +#include +#include +#ifdef CAIRO_HAS_PDF_SURFACE +#include +#endif +#ifdef CAIRO_HAS_PS_SURFACE +#include +#endif +#ifdef CAIRO_HAS_SVG_SURFACE +#include +#endif +#endif + +// stl +#include +#include +#include +#include + +namespace mapnik { + +#if defined(HAVE_CAIRO) +void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, double scale_factor, double scale_denominator) +{ + boost::optional type = type_from_filename(filename); + if (type) + { + save_to_cairo_file(map,filename,*type,scale_factor,scale_denominator); + } + else throw ImageWriterException("Could not write file to " + filename ); +} + +void save_to_cairo_file(mapnik::Map const& map, + std::string const& filename, + std::string const& type, + double scale_factor, + double scale_denominator) +{ + std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary); + if (file) + { + cairo_surface_ptr surface; + unsigned width = map.width(); + unsigned height = map.height(); + if (type == "pdf") + { +#ifdef CAIRO_HAS_PDF_SURFACE + surface = cairo_surface_ptr(cairo_pdf_surface_create(filename.c_str(),width,height),cairo_surface_closer()); +#else + throw ImageWriterException("PDFSurface not supported in the cairo backend"); +#endif + } +#ifdef CAIRO_HAS_SVG_SURFACE + else if (type == "svg") + { + surface = cairo_surface_ptr(cairo_svg_surface_create(filename.c_str(),width,height),cairo_surface_closer()); + } +#endif +#ifdef CAIRO_HAS_PS_SURFACE + else if (type == "ps") + { + surface = cairo_surface_ptr(cairo_ps_surface_create(filename.c_str(),width,height),cairo_surface_closer()); + } +#endif +#ifdef CAIRO_HAS_IMAGE_SURFACE + else if (type == "ARGB32") + { + surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,width,height),cairo_surface_closer()); + } + else if (type == "RGB24") + { + surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_RGB24,width,height),cairo_surface_closer()); + } +#endif + else + { + throw ImageWriterException("unknown file type: " + type); + } + + //cairo_t * ctx = cairo_create(surface); + + // TODO - expose as user option + /* + if (type == "ARGB32" || type == "RGB24") + { + context->set_antialias(Cairo::ANTIALIAS_NONE); + } + */ + + mapnik::cairo_renderer ren(map, create_context(surface), scale_factor); + ren.apply(scale_denominator); + + if (type == "ARGB32" || type == "RGB24") + { + cairo_surface_write_to_png(&*surface, filename.c_str()); + } + cairo_surface_finish(&*surface); + } +} + +#endif + +} // end ns diff --git a/src/color.cpp b/src/color.cpp index f1146e815..75204ce7f 100644 --- a/src/color.cpp +++ b/src/color.cpp @@ -45,9 +45,10 @@ namespace mapnik { -color::color(std::string const& str) +color::color(std::string const& str, bool premultiplied) { *this = parse_color(str); + premultiplied_ = premultiplied; } std::string color::to_string() const @@ -95,23 +96,28 @@ std::string color::to_hex_string() const return str; } -void color::premultiply() +bool color::premultiply() { + if (premultiplied_) return false; agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_); pre_c.premultiply(); red_ = pre_c.r; green_ = pre_c.g; blue_ = pre_c.b; + premultiplied_ = true; + return true; } -void color::demultiply() +bool color::demultiply() { - // note: this darkens too much: https://github.com/mapnik/mapnik/issues/1519 + if (!premultiplied_) return false; agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_); pre_c.demultiply(); red_ = pre_c.r; green_ = pre_c.g; blue_ = pre_c.b; + premultiplied_ = false; + return true; } } diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index 42fad26a5..94bfa6bbb 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #if defined(GRID_RENDERER) #include @@ -44,17 +44,17 @@ namespace mapnik { #if defined(HAVE_CAIRO) -template class feature_style_processor >; +template class MAPNIK_DECL feature_style_processor >; #endif #if defined(SVG_RENDERER) -template class feature_style_processor > >; +template class MAPNIK_DECL feature_style_processor > >; #endif #if defined(GRID_RENDERER) -template class feature_style_processor >; +template class MAPNIK_DECL feature_style_processor >; #endif -template class feature_style_processor >; +template class MAPNIK_DECL feature_style_processor >; } diff --git a/src/graphics.cpp b/src/graphics.cpp deleted file mode 100644 index 850df6514..000000000 --- a/src/graphics.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2014 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 -#include -#include -#include - -// agg -#include "agg_rendering_buffer.h" -#include "agg_pixfmt_rgba.h" -#include "agg_color_rgba.h" - -#ifdef HAVE_CAIRO -#include -#endif - -namespace mapnik -{ -image_32::image_32(int width,int height) - : data_(width,height), - painted_(false), - premultiplied_(false) {} - - -image_32::image_32(image_32 const& rhs) - : data_(rhs.data_), - painted_(rhs.painted_), - premultiplied_(rhs.premultiplied_) {} - -image_32::image_32(image_data_rgba8 && data) - : data_(std::move(data)), - painted_(false), - premultiplied_(false) {} - -image_32::~image_32() {} - -void image_32::set_grayscale_to_alpha() -{ - for (unsigned int y = 0; y < data_.height(); ++y) - { - unsigned int* row_from = data_.getRow(y); - for (unsigned int x = 0; x < data_.width(); ++x) - { - unsigned rgba = row_from[x]; - unsigned r = rgba & 0xff; - unsigned g = (rgba >> 8 ) & 0xff; - unsigned b = (rgba >> 16) & 0xff; - - // magic numbers for grayscale - unsigned a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); - - row_from[x] = (a << 24)| (255 << 16) | (255 << 8) | (255) ; - } - } -} - -void image_32::set_color_to_alpha(const color& c) -{ - for (unsigned y = 0; y < data_.height(); ++y) - { - unsigned int* row_from = data_.getRow(y); - for (unsigned x = 0; x < data_.width(); ++x) - { - unsigned rgba = row_from[x]; - unsigned r = rgba & 0xff; - unsigned g = (rgba >> 8 ) & 0xff; - unsigned b = (rgba >> 16) & 0xff; - if (r == c.red() && g == c.green() && b == c.blue()) - { - row_from[x] = 0; - } - } - } -} - -void image_32::set_alpha(float opacity) -{ - for (unsigned int y = 0; y < data_.height(); ++y) - { - unsigned int* row_to = data_.getRow(y); - for (unsigned int x = 0; x < data_.width(); ++x) - { - unsigned rgba = row_to[x]; - unsigned a0 = (rgba >> 24) & 0xff; - unsigned a1 = int( ((rgba >> 24) & 0xff) * opacity ); - //unsigned a1 = opacity; - if (a0 == a1) continue; - - unsigned r = rgba & 0xff; - unsigned g = (rgba >> 8 ) & 0xff; - unsigned b = (rgba >> 16) & 0xff; - - row_to[x] = (a1 << 24)| (b << 16) | (g << 8) | (r) ; - } - } -} - -void image_32::set_background(const color& c) -{ - background_=c; - data_.set(background_->rgba()); -} - -boost::optional const& image_32::get_background() const -{ - return background_; -} - -void image_32::premultiply() -{ - agg::rendering_buffer buffer(data_.getBytes(),data_.width(),data_.height(),data_.width() * 4); - agg::pixfmt_rgba32 pixf(buffer); - pixf.premultiply(); - premultiplied_ = true; -} - -void image_32::demultiply() -{ - agg::rendering_buffer buffer(data_.getBytes(),data_.width(),data_.height(),data_.width() * 4); - agg::pixfmt_rgba32_pre pixf(buffer); - pixf.demultiply(); - premultiplied_ = false; -} - -void image_32::composite_pixel(unsigned op, int x,int y, unsigned c, unsigned cover, double opacity) -{ - using color_type = agg::rgba8; - using value_type = color_type::value_type; - using order_type = agg::order_rgba; - using blender_type = agg::comp_op_adaptor_rgba; - - if (checkBounds(x,y)) - { - unsigned rgba = data_(x,y); - unsigned ca = (unsigned)(((c >> 24) & 0xff) * opacity); - unsigned cb = (c >> 16 ) & 0xff; - unsigned cg = (c >> 8) & 0xff; - unsigned cr = (c & 0xff); - blender_type::blend_pix(op, (value_type*)&rgba, cr, cg, cb, ca, cover); - data_(x,y) = rgba; - } -} - -} diff --git a/src/grid/grid.cpp b/src/grid/grid.cpp index 434e1bca9..0afefed28 100644 --- a/src/grid/grid.cpp +++ b/src/grid/grid.cpp @@ -34,7 +34,7 @@ namespace mapnik { template -const typename hit_grid::value_type hit_grid::base_mask = std::numeric_limits::min(); +const typename hit_grid::value_type hit_grid::base_mask = std::numeric_limits::min(); template hit_grid::hit_grid(int width, int height, std::string const& key, unsigned int resolution) @@ -146,7 +146,7 @@ void hit_grid::add_feature(mapnik::feature_impl const& feature) } -template class hit_grid; +template class MAPNIK_DECL hit_grid; } diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index c72f9d1ca..e48444242 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -125,10 +125,27 @@ void grid_renderer::end_layer_processing(layer const&) MAPNIK_LOG_DEBUG(grid_renderer) << "grid_renderer: End layer processing"; } -template -void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity, composite_mode_e /*comp_op*/) +template +struct grid_render_marker_visitor { - if (marker.is_vector()) + grid_render_marker_visitor(buffer_type & pixmap, + std::unique_ptr const& ras_ptr, + renderer_common const& common, + mapnik::feature_impl const& feature, + pixel_position const& pos, + agg::trans_affine const& tr, + double opacity) + : pixmap_(pixmap), + ras_ptr_(ras_ptr), + common_(common), + feature_(feature), + pos_(pos), + tr_(tr), + opacity_(opacity) {} + + void operator() (marker_null const&) {} + + void operator() (marker_svg const& marker) { using pixfmt_type = typename grid_renderer_base_type::pixfmt_type; using renderer_type = agg::renderer_scanline_bin_solid; @@ -140,61 +157,88 @@ void grid_renderer::render_marker(mapnik::feature_impl const& feature, pixel_ grid_renderer_base_type renb(pixf); renderer_type ren(renb); - ras_ptr->reset(); + ras_ptr_->reset(); - box2d const& bbox = (*marker.get_vector_data())->bounding_box(); + box2d const& bbox = marker.get_data()->bounding_box(); coord c = bbox.center(); // center the svg marker on '0,0' agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); // apply symbol transformation to get to map space - mtx *= tr; + mtx *= tr_; mtx *= agg::trans_affine_scaling(common_.scale_factor_); // render the marker at the center of the marker box - mtx.translate(pos.x, pos.y); + mtx.translate(pos_.x, pos_.y); using namespace mapnik::svg; - vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + vertex_stl_adapter stl_storage(marker.get_data()->source()); svg_path_adapter svg_path(stl_storage); svg_renderer_agg, renderer_type, pixfmt_type> svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); - - svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), mtx, opacity, bbox); + marker.get_data()->attributes()); + svg_renderer.render_id(*ras_ptr_, sl, renb, feature_.id(), mtx, opacity_, bbox); } - else + + void operator() (marker_rgba8 const& marker) { - image_data_rgba8 const& data = **marker.get_bitmap_data(); + image_rgba8 const& data = marker.get_data(); double width = data.width(); double height = data.height(); double cx = 0.5 * width; double cy = 0.5 * height; - if ((std::fabs(1.0 - common_.scale_factor_) < 0.001 && tr.is_identity())) + if ((std::fabs(1.0 - common_.scale_factor_) < 0.001 && tr_.is_identity())) { // TODO - support opacity - pixmap_.set_rectangle(feature.id(), data, - boost::math::iround(pos.x - cx), - boost::math::iround(pos.y - cy)); + pixmap_.set_rectangle(feature_.id(), data, + boost::math::iround(pos_.x - cx), + boost::math::iround(pos_.y - cy)); } else { - image_data_rgba8 target(data.width(), data.height()); + image_rgba8 target(data.width(), data.height()); mapnik::scale_image_agg(target, data, SCALING_NEAR, 1, 1, 0.0, 0.0, 1.0); // TODO: is 1.0 a valid default here, and do we even care in grid_renderer what the image looks like? - pixmap_.set_rectangle(feature.id(), target, - boost::math::iround(pos.x - cx), - boost::math::iround(pos.y - cy)); + pixmap_.set_rectangle(feature_.id(), target, + boost::math::iround(pos_.x - cx), + boost::math::iround(pos_.y - cy)); } } + + private: + buffer_type & pixmap_; + std::unique_ptr const& ras_ptr_; + renderer_common const& common_; + mapnik::feature_impl const& feature_; + pixel_position const& pos_; + agg::trans_affine const& tr_; + double opacity_; +}; + +template +void grid_renderer::render_marker(mapnik::feature_impl const& feature, + pixel_position const& pos, + marker const& marker, + agg::trans_affine const& tr, + double opacity, + composite_mode_e /*comp_op*/) +{ + grid_render_marker_visitor visitor(pixmap_, + ras_ptr, + common_, + feature, + pos, + tr, + opacity); + util::apply_visitor(visitor, marker); pixmap_.add_feature(feature); } -template class grid_renderer; +template class MAPNIK_DECL grid_renderer; } diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp index 8be4562c7..1931f9ce4 100644 --- a/src/grid/process_group_symbolizer.cpp +++ b/src/grid/process_group_symbolizer.cpp @@ -120,7 +120,7 @@ struct thunk_renderer render_raster_marker(ren, ras_, thunk.src_, feature_, offset_tr, thunk.opacity_); pixmap_.add_feature(feature_); } - + void operator()(text_render_thunk const &thunk) const { text_renderer_type ren(pixmap_, thunk.comp_op_, common_.scale_factor_); @@ -135,7 +135,7 @@ struct thunk_renderer { ren_.render_marker(feature_, glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, thunk.opacity_, thunk.comp_op_); } diff --git a/src/grid/process_line_pattern_symbolizer.cpp b/src/grid/process_line_pattern_symbolizer.cpp index 5f831c261..3a5a2e66c 100644 --- a/src/grid/process_line_pattern_symbolizer.cpp +++ b/src/grid/process_line_pattern_symbolizer.cpp @@ -53,18 +53,15 @@ void grid_renderer::process(line_pattern_symbolizer const& sym, { std::string filename = get(sym, feature, common_.vars_); if (filename.empty()) return; - boost::optional mark = marker_cache::instance().find(filename, true); - if (!mark) return; + mapnik::marker const& mark = marker_cache::instance().find(filename, true); + if (mark.is()) return; - if (!(*mark)->is_bitmap()) + if (!mark.is()) { MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer"; return; } - boost::optional pat = (*mark)->get_bitmap_data(); - if (!pat) return; - value_bool clip = get(sym, feature, common_.vars_); value_double offset = get(sym, feature, common_.vars_); value_double simplify_tolerance = get(sym, feature, common_.vars_); @@ -84,7 +81,7 @@ void grid_renderer::process(line_pattern_symbolizer const& sym, ras_ptr->reset(); - int stroke_width = (*pat)->width(); + int stroke_width = mark.width(); agg::trans_affine tr; auto transform = get_optional(sym, keys::geometry_transform); diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 2d7fa49f9..8c6a6d7dd 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -146,7 +146,7 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatch::type; using PixMapType = typename std::tuple_element<2,RendererContext>::type; - raster_markers_rasterizer_dispatch(image_data_rgba8 & src, + raster_markers_rasterizer_dispatch(image_rgba8 const& src, agg::trans_affine const& marker_trans, markers_symbolizer const& sym, Detector & detector, @@ -165,6 +165,8 @@ struct raster_markers_rasterizer_dispatch : public raster_markers_dispatchsrc_ provided that converts + // the destination pixel type required. render_raster_marker(RendererType(renb_), ras_, this->src_, this->feature_, marker_tr, opacity); if (!placed_) { diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp index 9dc97a0c1..bab9a7eeb 100644 --- a/src/grid/process_polygon_pattern_symbolizer.cpp +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -52,18 +52,15 @@ void grid_renderer::process(polygon_pattern_symbolizer const& sym, { std::string filename = get(sym, feature, common_.vars_); if (filename.empty()) return; - boost::optional mark = marker_cache::instance().find(filename, true); - if (!mark) return; + mapnik::marker const& mark = marker_cache::instance().find(filename, true); + if (mark.is()) return; - if (!(*mark)->is_bitmap()) + if (!mark.is()) { MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: Only images (not '" << filename << "') are supported in the line_pattern_symbolizer"; return; } - boost::optional pat = (*mark)->get_bitmap_data(); - if (!pat) return; - ras_ptr->reset(); value_bool clip = get(sym, feature, common_.vars_); diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index 42f42dcd2..fbcbe342f 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -70,7 +70,7 @@ void grid_renderer::process(shield_symbolizer const& sym, { render_marker(feature, glyphs->marker_pos(), - *(glyphs->marker()->marker), + glyphs->marker()->marker, glyphs->marker()->transform, opacity, comp_op); } diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 75e9884d2..878b0a611 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -22,7 +22,8 @@ // mapnik #include -#include +#include +#include // boost #pragma GCC diagnostic push @@ -128,8 +129,8 @@ namespace detail { template struct rendering_buffer { - using image_data_type = T; - using pixel_type = typename image_data_type::pixel_type; + using image_type = T; + using pixel_type = typename image_type::pixel_type; using row_data = agg::const_row_info; rendering_buffer(T const& data) @@ -138,47 +139,54 @@ struct rendering_buffer uint8_t const* buf() const { return data_.getBytes(); } unsigned width() const { return data_.width();} unsigned height() const { return data_.height();} - int stride() const { return data_.width() * sizeof(pixel_type);} + int stride() const { return data_.getRowSize();} uint8_t const* row_ptr(int, int y, unsigned) {return row_ptr(y);} uint8_t const* row_ptr(int y) const { return reinterpret_cast(data_.getRow(y)); } row_data row (int y) const { return row_data(0, data_.width() - 1, row_ptr(y)); } - image_data_type const& data_; + image_type const& data_; }; -} +} // end detail ns template <> -MAPNIK_DECL void composite(image_data_rgba8 & dst, image_data_rgba8 const& src, composite_mode_e mode, +MAPNIK_DECL void composite(image_rgba8 & dst, image_rgba8 const& src, composite_mode_e mode, float opacity, int dx, - int dy, - bool premultiply_src) + int dy) { using color = agg::rgba8; using order = agg::order_rgba; - using const_rendering_buffer = detail::rendering_buffer; + using const_rendering_buffer = detail::rendering_buffer; using blender_type = agg::comp_op_adaptor_rgba_pre; using pixfmt_type = agg::pixfmt_custom_blend_rgba; using renderer_type = agg::renderer_base; - agg::rendering_buffer dst_buffer(dst.getBytes(),dst.width(),dst.height(),dst.width() * 4); + agg::rendering_buffer dst_buffer(dst.getBytes(),dst.width(),dst.height(),dst.getRowSize()); const_rendering_buffer src_buffer(src); pixfmt_type pixf(dst_buffer); pixf.comp_op(static_cast(mode)); agg::pixfmt_alpha_blend_rgba pixf_mask(src_buffer); - if (premultiply_src) pixf_mask.premultiply(); +#ifdef MAPNIK_DEBUG + if (!src.get_premultiplied()) + { + throw std::runtime_error("SOURCE MUST BE PREMULTIPLIED FOR COMPOSITING!"); + } + if (!dst.get_premultiplied()) + { + throw std::runtime_error("DESTINATION MUST BE PREMULTIPLIED FOR COMPOSITING!"); + } +#endif renderer_type ren(pixf); ren.blend_from(pixf_mask,0,dx,dy,unsigned(255*opacity)); } template <> -MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f const& src, composite_mode_e mode, +MAPNIK_DECL void composite(image_gray32f & dst, image_gray32f const& src, composite_mode_e mode, float opacity, int dx, - int dy, - bool premultiply_src) + int dy) { - using const_rendering_buffer = detail::rendering_buffer; + using const_rendering_buffer = detail::rendering_buffer; using src_pixfmt_type = agg::pixfmt_alpha_blend_gray, const_rendering_buffer, 1, 0>; using dst_pixfmt_type = agg::pixfmt_alpha_blend_gray, agg::rendering_buffer, 1, 0>; using renderer_type = agg::renderer_base; @@ -191,4 +199,59 @@ MAPNIK_DECL void composite(image_data_gray32f & dst, image_data_gray32f const& s ren.copy_from(pixf_mask,0,dx,dy); } +namespace detail { + +struct composite_visitor +{ + composite_visitor(image_any const& src, + composite_mode_e mode, + float opacity, + int dx, + int dy) + : src_(src), + mode_(mode), + opacity_(opacity), + dx_(dx), + dy_(dy) {} + + template + void operator() (T & dst); + + private: + image_any const& src_; + composite_mode_e mode_; + float opacity_; + int dx_; + int dy_; +}; + +template +void composite_visitor::operator() (T & dst) +{ + throw std::runtime_error("Error: Composite with " + std::string(typeid(dst).name()) + " is not supported"); +} + +template <> +void composite_visitor::operator() (image_rgba8 & dst) +{ + composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); +} + +template <> +void composite_visitor::operator() (image_gray32f & dst) +{ + composite(dst, util::get(src_), mode_, opacity_, dx_, dy_); +} + +} // end ns + +template <> +MAPNIK_DECL void composite(image_any & dst, image_any const& src, composite_mode_e mode, + float opacity, + int dx, + int dy) +{ + util::apply_visitor(detail::composite_visitor(src, mode, opacity, dx, dy), dst); +} + } diff --git a/src/image_copy.cpp b/src/image_copy.cpp new file mode 100644 index 000000000..e686576db --- /dev/null +++ b/src/image_copy.cpp @@ -0,0 +1,347 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +#include + +// boost +#include + +using boost::numeric_cast; +using boost::numeric::positive_overflow; +using boost::numeric::negative_overflow; + +namespace mapnik +{ + +namespace detail +{ + +template +struct visitor_image_copy +{ + using dst_type = typename T0::pixel_type; + + T0 operator() (image_null const&) + { + throw std::runtime_error("Can not cast a null image"); + } + + T0 operator() (T0 const& src) + { + return T0(src); + } + + template + T0 operator() (T1 const& src) + { + T0 dst(src.width(), src.height(), false); + for (unsigned y = 0; y < dst.height(); ++y) + { + for (unsigned x = 0; x < dst.width(); ++x) + { + try + { + dst(x,y) = numeric_cast(src(x,y)); + } + catch(negative_overflow&) + { + dst(x,y) = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + dst(x,y) = std::numeric_limits::max(); + } + } + } + return T0(std::move(dst)); + } +}; + +template +struct visitor_image_copy_so +{ + using dst_type = typename T0::pixel_type; + + visitor_image_copy_so(double offset, double scaling) + : offset_(offset), scaling_(scaling) {} + + T0 operator() (image_null const&) + { + throw std::runtime_error("Can not cast a null image"); + } + + T0 operator() (T0 const& src) + { + return T0(src); + } + + template + T0 operator() (T1 const& src) + { + double src_offset = src.get_offset(); + double src_scaling = src.get_scaling(); + T0 dst(src.width(), src.height(), false); + dst.set_scaling(scaling_); + dst.set_offset(offset_); + for (unsigned y = 0; y < dst.height(); ++y) + { + for (unsigned x = 0; x < dst.width(); ++x) + { + double scaled_src_val = (numeric_cast(src(x,y)) * src_scaling) + src_offset; + double dst_val = (scaled_src_val - offset_) / scaling_; + try + { + dst(x,y) = numeric_cast(dst_val); + } + catch(negative_overflow&) + { + dst(x,y) = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + dst(x,y) = std::numeric_limits::max(); + } + } + } + return T0(std::move(dst)); + } + private: + double offset_; + double scaling_; +}; + +} // end detail ns + +template +MAPNIK_DECL T image_copy(image_any const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + return util::apply_visitor(detail::visitor_image_copy(), data); + } + else + { + return util::apply_visitor(detail::visitor_image_copy_so(offset, scaling), data); + } +} + +template +MAPNIK_DECL T image_copy(image_rgba8 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray8 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray8s const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray16 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray16s const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray32 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray32s const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray32f const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray64 const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray64s const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +template +MAPNIK_DECL T image_copy(image_gray64f const& data, double offset, double scaling) +{ + if (offset == 0.0 && scaling == 1.0 && data.get_offset() == 0.0 && data.get_scaling() == 1.0) + { + detail::visitor_image_copy visit; + return visit(data); + } + else + { + detail::visitor_image_copy_so visit(offset, scaling); + return visit(data); + } +} + +MAPNIK_DECL image_any image_copy(image_any const& data, image_dtype type, double offset, double scaling) +{ + switch (type) + { + case image_dtype_rgba8: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray8: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray8s: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray16: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray16s: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray32: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray32s: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray32f: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray64: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray64s: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_gray64f: + return image_any(std::move(image_copy(data, offset, scaling))); + case image_dtype_null: + throw std::runtime_error("Can not cast a null image"); + } + throw std::runtime_error("Unknown image type passed"); +} + +} // end mapnik ns diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp index 7edf13e6e..42a96eb1c 100644 --- a/src/image_scaling.cpp +++ b/src/image_scaling.cpp @@ -21,7 +21,7 @@ *****************************************************************************/ // mapnik -#include +#include #include #include // does not handle alpha correctly @@ -107,12 +107,12 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho // http://old.nabble.com/Re:--AGG--Basic-image-transformations-p1110665.html // "Yes, you need to use premultiplied images only. Only in this case the simple weighted averaging works correctly in the image fitering." // http://permalink.gmane.org/gmane.comp.graphics.agg/3443 - using image_data_type = T; - using pixel_type = typename image_data_type::pixel_type; - using pixfmt_pre = typename detail::agg_scaling_traits::pixfmt_pre; - using color_type = typename detail::agg_scaling_traits::color_type; - using img_src_type = typename detail::agg_scaling_traits::img_src_type; - using interpolator_type = typename detail::agg_scaling_traits::interpolator_type; + using image_type = T; + using pixel_type = typename image_type::pixel_type; + using pixfmt_pre = typename detail::agg_scaling_traits::pixfmt_pre; + using color_type = typename detail::agg_scaling_traits::color_type; + using img_src_type = typename detail::agg_scaling_traits::img_src_type; + using interpolator_type = typename detail::agg_scaling_traits::interpolator_type; using renderer_base_pre = agg::renderer_base; constexpr std::size_t pixel_size = sizeof(pixel_type); @@ -150,13 +150,13 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho if (scaling_method == SCALING_NEAR) { - using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; + using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; span_gen_type sg(img_src, interpolator); agg::render_scanlines_aa(ras, sl, rb_dst_pre, sa, sg); } else { - using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; + using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; agg::image_filter_lut filter; detail::set_scaling_method(filter, scaling_method, filter_factor); span_gen_type sg(img_src, interpolator, filter); @@ -165,16 +165,36 @@ void scale_image_agg(T & target, T const& source, scaling_method_e scaling_metho } -template MAPNIK_DECL void scale_image_agg(image_data_rgba8 &, image_data_rgba8 const&, scaling_method_e, +template MAPNIK_DECL void scale_image_agg(image_rgba8 &, image_rgba8 const&, scaling_method_e, double, double , double, double , double); -template MAPNIK_DECL void scale_image_agg(image_data_gray8 &, image_data_gray8 const&, scaling_method_e, +template MAPNIK_DECL void scale_image_agg(image_gray8 &, image_gray8 const&, scaling_method_e, double, double , double, double , double); -template MAPNIK_DECL void scale_image_agg(image_data_gray16 &, image_data_gray16 const&, scaling_method_e, +template MAPNIK_DECL void scale_image_agg(image_gray8s &, image_gray8s const&, scaling_method_e, double, double , double, double , double); -template MAPNIK_DECL void scale_image_agg(image_data_gray32f &, image_data_gray32f const&, scaling_method_e, +template MAPNIK_DECL void scale_image_agg(image_gray16 &, image_gray16 const&, scaling_method_e, double, double , double, double , double); +template MAPNIK_DECL void scale_image_agg(image_gray16s &, image_gray16s const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray32 &, image_gray32 const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray32s &, image_gray32s const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray32f &, image_gray32f const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray64 &, image_gray64 const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray64s &, image_gray64s const&, scaling_method_e, + double, double , double, double , double); + +template MAPNIK_DECL void scale_image_agg(image_gray64f &, image_gray64f const&, scaling_method_e, + double, double , double, double , double); } diff --git a/src/image_util.cpp b/src/image_util.cpp index de81f9a90..0a861f128 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -20,68 +20,50 @@ * *****************************************************************************/ -#if defined(HAVE_PNG) -extern "C" -{ -#include -} -#endif - // mapnik -#if defined(HAVE_PNG) -#include -#endif - -#if defined(HAVE_TIFF) -#include -#endif - -#if defined(HAVE_JPEG) -#include -#endif - -#if defined(HAVE_WEBP) -#include -#endif - #include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include +#include +#include +#include +#ifdef SSE_MATH +#include -#ifdef HAVE_CAIRO -#include -#include -#ifdef CAIRO_HAS_PDF_SURFACE -#include -#endif -#ifdef CAIRO_HAS_PS_SURFACE -#include -#endif -#ifdef CAIRO_HAS_SVG_SURFACE -#include -#endif -#endif +#endif -// boost -#include +// agg +#include "agg_rendering_buffer.h" +#include "agg_pixfmt_rgba.h" +#include "agg_color_rgba.h" // stl #include -#include #include #include #include +// boost +#include + + +using boost::numeric_cast; +using boost::numeric::positive_overflow; +using boost::numeric::negative_overflow; + namespace mapnik { - template -std::string save_to_string(T const& image, +MAPNIK_DECL std::string save_to_string(T const& image, std::string const& type, rgba_palette const& palette) { @@ -91,7 +73,7 @@ std::string save_to_string(T const& image, } template -std::string save_to_string(T const& image, +MAPNIK_DECL std::string save_to_string(T const& image, std::string const& type) { std::ostringstream ss(std::ios::out|std::ios::binary); @@ -100,7 +82,7 @@ std::string save_to_string(T const& image, } template -void save_to_file(T const& image, +MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, std::string const& type, rgba_palette const& palette) @@ -108,564 +90,26 @@ void save_to_file(T const& image, std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); if (file) { - save_to_stream(image, file, type, palette); + save_to_stream(image, file, type, palette); } else throw ImageWriterException("Could not write file to " + filename ); } template -void save_to_file(T const& image, +MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, std::string const& type) { std::ofstream file (filename.c_str(), std::ios::out| std::ios::trunc|std::ios::binary); if (file) { - save_to_stream(image, file, type); + save_to_stream(image, file, type); } else throw ImageWriterException("Could not write file to " + filename ); } -#if defined(HAVE_PNG) - -void handle_png_options(std::string const& type, - png_options & opts) -{ - if (type == "png" || type == "png24" || type == "png32") - { - opts.paletted = false; - return; - } - else if (type == "png8" || type == "png256") - { - opts.paletted = true; - return; - } - boost::char_separator sep(":"); - boost::tokenizer< boost::char_separator > tokens(type, sep); - bool set_colors = false; - bool set_gamma = false; - for (std::string const& t : tokens) - { - if (t == "png8" || t == "png256") - { - opts.paletted = true; - } - else if (t == "png" || t == "png24" || t == "png32") - { - opts.paletted = false; - } - else if (t == "m=o") - { - opts.use_hextree = false; - } - else if (t == "m=h") - { - opts.use_hextree = true; - } - else if (t == "e=miniz") - { - opts.use_miniz = true; - } - else if (boost::algorithm::starts_with(t, "c=")) - { - set_colors = true; - if (!mapnik::util::string2int(t.substr(2),opts.colors) || opts.colors < 1 || opts.colors > 256) - { - throw ImageWriterException("invalid color parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "t=")) - { - if (!mapnik::util::string2int(t.substr(2),opts.trans_mode) || opts.trans_mode < 0 || opts.trans_mode > 2) - { - throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "g=")) - { - set_gamma = true; - if (!mapnik::util::string2double(t.substr(2),opts.gamma) || opts.gamma < 0) - { - throw ImageWriterException("invalid gamma parameter: " + t.substr(2)); - } - } - else if (boost::algorithm::starts_with(t, "z=")) - { - /* - #define Z_NO_COMPRESSION 0 - #define Z_BEST_SPEED 1 - #define Z_BEST_COMPRESSION 9 - #define Z_DEFAULT_COMPRESSION (-1) - */ - if (!mapnik::util::string2int(t.substr(2),opts.compression) - || opts.compression < Z_DEFAULT_COMPRESSION - || opts.compression > 10) // use 10 here rather than Z_BEST_COMPRESSION (9) to allow for MZ_UBER_COMPRESSION - { - throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 10 are valid)"); - } - } - else if (boost::algorithm::starts_with(t, "s=")) - { - std::string s = t.substr(2); - if (s == "default") - { - opts.strategy = Z_DEFAULT_STRATEGY; - } - else if (s == "filtered") - { - opts.strategy = Z_FILTERED; - } - else if (s == "huff") - { - opts.strategy = Z_HUFFMAN_ONLY; - } - else if (s == "rle") - { - opts.strategy = Z_RLE; - } - else if (s == "fixed") - { - opts.strategy = Z_FIXED; - } - else - { - throw ImageWriterException("invalid compression strategy parameter: " + s); - } - } - else - { - throw ImageWriterException("unhandled png option: " + t); - } - } - // validation - if (!opts.paletted && set_colors) - { - throw ImageWriterException("invalid color parameter: unavailable for true color (non-paletted) images"); - } - if (!opts.paletted && set_gamma) - { - throw ImageWriterException("invalid gamma parameter: unavailable for true color (non-paletted) images"); - } - if ((opts.use_miniz == false) && opts.compression > Z_BEST_COMPRESSION) - { - throw ImageWriterException("invalid compression value: (only -1 through 9 are valid)"); - } -} -#endif - -#if defined(HAVE_TIFF) -void handle_tiff_options(std::string const& type, - tiff_config & config) -{ - if (type == "tiff") - { - return; - } - if (type.length() > 4) - { - boost::char_separator sep(":"); - boost::tokenizer< boost::char_separator > tokens(type, sep); - for (auto const& t : tokens) - { - if (t == "tiff") - { - continue; - } - else if (boost::algorithm::starts_with(t, "compression=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - if (val == "deflate") - { - config.compression = COMPRESSION_DEFLATE; - } - else if (val == "adobedeflate") - { - config.compression = COMPRESSION_ADOBE_DEFLATE; - } - else if (val == "lzw") - { - config.compression = COMPRESSION_LZW; - } - else if (val == "none") - { - config.compression = COMPRESSION_NONE; - } - else - { - throw ImageWriterException("invalid tiff compression: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "method=")) - { - std::string val = t.substr(7); - if (!val.empty()) - { - if (val == "scanline") - { - config.method = TIFF_WRITE_SCANLINE; - } - else if (val == "strip" || val == "stripped") - { - config.method = TIFF_WRITE_STRIPPED; - } - else if (val == "tiled") - { - config.method = TIFF_WRITE_TILED; - } - else - { - throw ImageWriterException("invalid tiff method: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "zlevel=")) - { - std::string val = t.substr(7); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.zlevel) || config.zlevel < 0 || config.zlevel > 9) - { - throw ImageWriterException("invalid tiff zlevel: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "tile_height=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.tile_height) || config.tile_height < 0 ) - { - throw ImageWriterException("invalid tiff tile_height: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "tile_width=")) - { - std::string val = t.substr(11); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.tile_width) || config.tile_width < 0 ) - { - throw ImageWriterException("invalid tiff tile_width: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "rows_per_strip=")) - { - std::string val = t.substr(15); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.rows_per_strip) || config.rows_per_strip < 0 ) - { - throw ImageWriterException("invalid tiff rows_per_strip: '" + val + "'"); - } - } - } - else - { - throw ImageWriterException("unhandled tiff option: " + t); - } - } - } -} -#endif - -#if defined(HAVE_WEBP) -void handle_webp_options(std::string const& type, - WebPConfig & config, - bool & alpha) -{ - if (type == "webp") - { - return; - } - if (type.length() > 4){ - boost::char_separator sep(":"); - boost::tokenizer< boost::char_separator > tokens(type, sep); - for (auto const& t : tokens) - { - if (t == "webp") - { - continue; - } - else if (boost::algorithm::starts_with(t, "quality=")) - { - std::string val = t.substr(8); - if (!val.empty()) - { - double quality = 90; - if (!mapnik::util::string2double(val,quality) || quality < 0.0 || quality > 100.0) - { - throw ImageWriterException("invalid webp quality: '" + val + "'"); - } - config.quality = static_cast(quality); - } - } - else if (boost::algorithm::starts_with(t, "method=")) - { - std::string val = t.substr(7); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.method) || config.method < 0 || config.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 (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 - if (!mapnik::util::string2int(val,config.lossless) || config.lossless < 0 || config.lossless > 1) - { - throw ImageWriterException("invalid webp lossless: '" + val + "'"); - } - #else - #ifdef _MSC_VER - #pragma NOTE(compiling against webp that does not support the lossless flag) - #else - #warning "compiling against webp that does not support the lossless flag" - #endif - throw ImageWriterException("your webp version does not support the lossless option"); - #endif - } - } - else if (boost::algorithm::starts_with(t, "image_hint=")) - { - std::string val = t.substr(11); - if (!val.empty()) - { - #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 - int image_hint = 0; - if (!mapnik::util::string2int(val,image_hint) || image_hint < 0 || image_hint > 3) - { - throw ImageWriterException("invalid webp image_hint: '" + val + "'"); - } - config.image_hint = static_cast(image_hint); - #else - #ifdef _MSC_VER - #pragma NOTE(compiling against webp that does not support the image_hint flag) - #else - #warning "compiling against webp that does not support the image_hint flag" - #endif - throw ImageWriterException("your webp version does not support the image_hint option"); - #endif - } - } - else if (boost::algorithm::starts_with(t, "alpha=")) - { - std::string val = t.substr(6); - if (!val.empty()) - { - if (!mapnik::util::string2bool(val,alpha)) - { - throw ImageWriterException("invalid webp alpha: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "target_size=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.target_size)) - { - throw ImageWriterException("invalid webp target_size: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "target_psnr=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - double psnr = 0; - if (!mapnik::util::string2double(val,psnr)) - { - throw ImageWriterException("invalid webp target_psnr: '" + val + "'"); - } - config.target_PSNR = psnr; - } - } - else if (boost::algorithm::starts_with(t, "segments=")) - { - std::string val = t.substr(9); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.segments)) - { - throw ImageWriterException("invalid webp segments: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "sns_strength=")) - { - std::string val = t.substr(13); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.sns_strength)) - { - throw ImageWriterException("invalid webp sns_strength: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "filter_strength=")) - { - std::string val = t.substr(16); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.filter_strength)) - { - throw ImageWriterException("invalid webp filter_strength: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "filter_sharpness=")) - { - std::string val = t.substr(17); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.filter_sharpness)) - { - throw ImageWriterException("invalid webp filter_sharpness: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "filter_type=")) - { - std::string val = t.substr(12); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.filter_type)) - { - throw ImageWriterException("invalid webp filter_type: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "autofilter=")) - { - std::string val = t.substr(11); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.autofilter)) - { - throw ImageWriterException("invalid webp autofilter: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "alpha_compression=")) - { - std::string val = t.substr(18); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.alpha_compression)) - { - throw ImageWriterException("invalid webp alpha_compression: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "alpha_filtering=")) - { - std::string val = t.substr(16); - if (!val.empty()) - { - #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 - if (!mapnik::util::string2int(val,config.alpha_filtering)) - { - throw ImageWriterException("invalid webp alpha_filtering: '" + val + "'"); - } - #else - #ifdef _MSC_VER - #pragma NOTE(compiling against webp that does not support the alpha_filtering flag) - #else - #warning "compiling against webp that does not support the alpha_filtering flag" - #endif - throw ImageWriterException("your webp version does not support the alpha_filtering option"); - #endif - } - } - else if (boost::algorithm::starts_with(t, "alpha_quality=")) - { - std::string val = t.substr(14); - if (!val.empty()) - { - #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 - if (!mapnik::util::string2int(val,config.alpha_quality)) - { - throw ImageWriterException("invalid webp alpha_quality: '" + val + "'"); - } - #else - #ifdef _MSC_VER - #pragma NOTE(compiling against webp that does not support the alpha_quality flag) - #else - #warning "compiling against webp that does not support the alpha_quality flag" - #endif - throw ImageWriterException("your webp version does not support the alpha_quality option"); - #endif - } - } - else if (boost::algorithm::starts_with(t, "pass=")) - { - std::string val = t.substr(5); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.pass)) - { - throw ImageWriterException("invalid webp pass: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "preprocessing=")) - { - std::string val = t.substr(14); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.preprocessing)) - { - throw ImageWriterException("invalid webp preprocessing: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "partitions=")) - { - std::string val = t.substr(11); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.partitions)) - { - throw ImageWriterException("invalid webp partitions: '" + val + "'"); - } - } - } - else if (boost::algorithm::starts_with(t, "partition_limit=")) - { - std::string val = t.substr(16); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,config.partition_limit)) - { - throw ImageWriterException("invalid webp partition_limit: '" + val + "'"); - } - } - } - else - { - throw ImageWriterException("unhandled webp option: " + t); - } - } - } -} -#endif - template -void save_to_stream(T const& image, +MAPNIK_DECL void save_to_stream(T const& image, std::ostream & stream, std::string const& type, rgba_palette const& palette) @@ -676,20 +120,8 @@ void save_to_stream(T const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { -#if defined(HAVE_PNG) - if (palette.valid()) - { - png_options opts; - handle_png_options(t,opts); - save_as_png8_pal(stream, image, palette, opts); - } - else - { - save_to_stream(image,stream,type); - } -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif + png_saver_pal visitor(stream, t, palette); + mapnik::util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "tif")) { @@ -704,9 +136,70 @@ void save_to_stream(T const& image, else throw ImageWriterException("Could not write to empty stream" ); } +// This can be removed once image_any and image_view_any are the only +// items using this template +template <> +MAPNIK_DECL void save_to_stream(image_rgba8 const& image, + std::ostream & stream, + std::string const& type, + rgba_palette const& palette) +{ + if (stream && image.width() > 0 && image.height() > 0) + { + std::string t = type; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + if (t == "png" || boost::algorithm::starts_with(t, "png")) + { + png_saver_pal visitor(stream, t, palette); + visitor(image); + //mapnik::util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "tif")) + { + throw ImageWriterException("palettes are not currently supported when writing to tiff format (yet)"); + } + else if (boost::algorithm::starts_with(t, "jpeg")) + { + throw ImageWriterException("palettes are not currently supported when writing to jpeg format"); + } + else throw ImageWriterException("unknown file type: " + type); + } + else throw ImageWriterException("Could not write to empty stream" ); +} + +// This can be removed once image_any and image_view_any are the only +// items using this template +template <> +MAPNIK_DECL void save_to_stream(image_view_rgba8 const& image, + std::ostream & stream, + std::string const& type, + rgba_palette const& palette) +{ + if (stream && image.width() > 0 && image.height() > 0) + { + std::string t = type; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + if (t == "png" || boost::algorithm::starts_with(t, "png")) + { + png_saver_pal visitor(stream, t, palette); + visitor(image); + //mapnik::util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "tif")) + { + throw ImageWriterException("palettes are not currently supported when writing to tiff format (yet)"); + } + else if (boost::algorithm::starts_with(t, "jpeg")) + { + throw ImageWriterException("palettes are not currently supported when writing to jpeg format"); + } + else throw ImageWriterException("unknown file type: " + type); + } + else throw ImageWriterException("Could not write to empty stream" ); +} template -void save_to_stream(T const& image, +MAPNIK_DECL void save_to_stream(T const& image, std::ostream & stream, std::string const& type) { @@ -716,71 +209,103 @@ void save_to_stream(T const& image, std::transform(t.begin(), t.end(), t.begin(), ::tolower); if (t == "png" || boost::algorithm::starts_with(t, "png")) { -#if defined(HAVE_PNG) - png_options opts; - handle_png_options(t,opts); - if (opts.paletted) - { - if (opts.use_hextree) - { - save_as_png8_hex(stream, image, opts); - } - else - { - save_as_png8_oct(stream, image, opts); - } - } - else - { - save_as_png(stream, image, opts); - } -#else - throw ImageWriterException("png output is not enabled in your build of Mapnik"); -#endif + png_saver visitor(stream, t); + util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "tif")) { -#if defined(HAVE_TIFF) - tiff_config config; - handle_tiff_options(t, config); - save_as_tiff(stream, image, config); -#else - throw ImageWriterException("tiff output is not enabled in your build of Mapnik"); -#endif + tiff_saver visitor(stream, t); + util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "jpeg")) { -#if defined(HAVE_JPEG) - int quality = 85; - std::string val = t.substr(4); - if (!val.empty()) - { - if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100) - { - throw ImageWriterException("invalid jpeg quality: '" + val + "'"); - } - } - save_as_jpeg(stream, quality, image); -#else - throw ImageWriterException("jpeg output is not enabled in your build of Mapnik"); -#endif + jpeg_saver visitor(stream, t); + util::apply_visitor(visitor, image); } else if (boost::algorithm::starts_with(t, "webp")) { -#if defined(HAVE_WEBP) - WebPConfig config; - // Default values set here will be lossless=0 and quality=75 (as least as of webp v0.3.1) - if (!WebPConfigInit(&config)) - { - throw std::runtime_error("version mismatch"); - } - // see for more details: https://github.com/mapnik/mapnik/wiki/Image-IO#webp-output-options - bool alpha = true; - handle_webp_options(t,config,alpha); - save_as_webp(stream,image,config,alpha); -#else - throw ImageWriterException("webp output is not enabled in your build of Mapnik"); -#endif + webp_saver visitor(stream, t); + util::apply_visitor(visitor, image); + } + else throw ImageWriterException("unknown file type: " + type); + } + else throw ImageWriterException("Could not write to empty stream" ); +} + +// This can be removed once image_any and image_view_any are the only +// items using this template +template <> +MAPNIK_DECL void save_to_stream(image_rgba8 const& image, + std::ostream & stream, + std::string const& type) +{ + if (stream && image.width() > 0 && image.height() > 0) + { + std::string t = type; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + if (t == "png" || boost::algorithm::starts_with(t, "png")) + { + png_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "tif")) + { + tiff_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "jpeg")) + { + jpeg_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "webp")) + { + webp_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else throw ImageWriterException("unknown file type: " + type); + } + else throw ImageWriterException("Could not write to empty stream" ); +} + +// This can be removed once image_any and image_view_any are the only +// items using this template +template <> +MAPNIK_DECL void save_to_stream(image_view_rgba8 const& image, + std::ostream & stream, + std::string const& type) +{ + if (stream && image.width() > 0 && image.height() > 0) + { + std::string t = type; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + if (t == "png" || boost::algorithm::starts_with(t, "png")) + { + png_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "tif")) + { + tiff_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "jpeg")) + { + jpeg_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); + } + else if (boost::algorithm::starts_with(t, "webp")) + { + webp_saver visitor(stream, t); + visitor(image); + //util::apply_visitor(visitor, image); } else throw ImageWriterException("unknown file type: " + type); } @@ -788,7 +313,7 @@ void save_to_stream(T const& image, } template -void save_to_file(T const& image, std::string const& filename) +MAPNIK_DECL void save_to_file(T const& image, std::string const& filename) { boost::optional type = type_from_filename(filename); if (type) @@ -799,7 +324,7 @@ void save_to_file(T const& image, std::string const& filename) } template -void save_to_file(T const& image, std::string const& filename, rgba_palette const& palette) +MAPNIK_DECL void save_to_file(T const& image, std::string const& filename, rgba_palette const& palette) { boost::optional type = type_from_filename(filename); if (type) @@ -809,132 +334,2128 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons else throw ImageWriterException("Could not write file to " + filename ); } -#if defined(HAVE_CAIRO) -// TODO - move to separate cairo_io.hpp -void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, double scale_factor, double scale_denominator) +// image_rgba8 +template MAPNIK_DECL void save_to_file(image_rgba8 const&, + std::string const&, + std::string const&); + +template MAPNIK_DECL void save_to_file(image_rgba8 const&, + std::string const&, + std::string const&, + rgba_palette const& palette); + +template MAPNIK_DECL void save_to_file(image_rgba8 const&, + std::string const&); + +template MAPNIK_DECL void save_to_file(image_rgba8 const&, + std::string const&, + rgba_palette const& palette); + +template MAPNIK_DECL std::string save_to_string(image_rgba8 const&, + std::string const&); + +template MAPNIK_DECL std::string save_to_string(image_rgba8 const&, + std::string const&, + rgba_palette const& palette); + +// image_view_any +template MAPNIK_DECL void save_to_file (image_view_any const&, + std::string const&, + std::string const&); + +template MAPNIK_DECL void save_to_file (image_view_any const&, + std::string const&, + std::string const&, + rgba_palette const& palette); + +template MAPNIK_DECL void save_to_file (image_view_any const&, + std::string const&); + +template MAPNIK_DECL void save_to_file (image_view_any const&, + std::string const&, + rgba_palette const& palette); + +template MAPNIK_DECL std::string save_to_string (image_view_any const&, + std::string const&); + +template MAPNIK_DECL std::string save_to_string (image_view_any const&, + std::string const&, + rgba_palette const& palette); + +// image_any +template MAPNIK_DECL void save_to_file(image_any const&, + std::string const&, + std::string const&); + +template MAPNIK_DECL void save_to_file(image_any const&, + std::string const&, + std::string const&, + rgba_palette const& palette); + +template MAPNIK_DECL void save_to_file(image_any const&, + std::string const&); + +template MAPNIK_DECL void save_to_file(image_any const&, + std::string const&, + rgba_palette const& palette); + +template MAPNIK_DECL std::string save_to_string(image_any const&, + std::string const&); + +template MAPNIK_DECL std::string save_to_string(image_any const&, + std::string const&, + rgba_palette const& palette); + +namespace detail { + +struct is_solid_visitor { - boost::optional type = type_from_filename(filename); - if (type) + bool operator() (image_null const&) { - save_to_cairo_file(map,filename,*type,scale_factor,scale_denominator); + return true; } - else throw ImageWriterException("Could not write file to " + filename ); + + template + bool operator() (T const & data) + { + using pixel_type = typename T::pixel_type; + if (data.width() > 0 && data.height() > 0) + { + pixel_type const* first_row = data.getRow(0); + pixel_type const first_pixel = first_row[0]; + for (unsigned y = 0; y < data.height(); ++y) + { + pixel_type const * row = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + if (first_pixel != row[x]) + { + return false; + } + } + } + } + return true; + } +}; + +} // end detail ns + +MAPNIK_DECL bool is_solid(image_any const& image) +{ + return util::apply_visitor(detail::is_solid_visitor(), image); } -void save_to_cairo_file(mapnik::Map const& map, - std::string const& filename, - std::string const& type, - double scale_factor, - double scale_denominator) +MAPNIK_DECL bool is_solid(image_view_any const& image) { - std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary); - if (file) + return util::apply_visitor(detail::is_solid_visitor(), image); +} + +template +MAPNIK_DECL bool is_solid(T const& image) +{ + detail::is_solid_visitor visitor; + return visitor(image); +} + +template MAPNIK_DECL bool is_solid(image_rgba8 const&); +template MAPNIK_DECL bool is_solid(image_gray8 const&); +template MAPNIK_DECL bool is_solid(image_gray8s const&); +template MAPNIK_DECL bool is_solid(image_gray16 const&); +template MAPNIK_DECL bool is_solid(image_gray16s const&); +template MAPNIK_DECL bool is_solid(image_gray32 const&); +template MAPNIK_DECL bool is_solid(image_gray32s const&); +template MAPNIK_DECL bool is_solid(image_gray32f const&); +template MAPNIK_DECL bool is_solid(image_gray64 const&); +template MAPNIK_DECL bool is_solid(image_gray64s const&); +template MAPNIK_DECL bool is_solid(image_gray64f const&); + +namespace detail { + +struct premultiply_visitor +{ + bool operator() (image_rgba8 & data) { - cairo_surface_ptr surface; - unsigned width = map.width(); - unsigned height = map.height(); - if (type == "pdf") + if (!data.get_premultiplied()) { -#ifdef CAIRO_HAS_PDF_SURFACE - surface = cairo_surface_ptr(cairo_pdf_surface_create(filename.c_str(),width,height),cairo_surface_closer()); -#else - throw ImageWriterException("PDFSurface not supported in the cairo backend"); -#endif + agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.getRowSize()); + agg::pixfmt_rgba32 pixf(buffer); + pixf.premultiply(); + data.set_premultiplied(true); + return true; } -#ifdef CAIRO_HAS_SVG_SURFACE - else if (type == "svg") + return false; + } + + template + bool operator() (T &) + { + return false; + } +}; + +struct demultiply_visitor +{ + bool operator() (image_rgba8 & data) + { + if (data.get_premultiplied()) { - surface = cairo_surface_ptr(cairo_svg_surface_create(filename.c_str(),width,height),cairo_surface_closer()); + agg::rendering_buffer buffer(data.getBytes(),data.width(),data.height(),data.getRowSize()); + agg::pixfmt_rgba32_pre pixf(buffer); + pixf.demultiply(); + data.set_premultiplied(false); + return true; } -#endif -#ifdef CAIRO_HAS_PS_SURFACE - else if (type == "ps") + return false; + } + + template + bool operator() (T &) + { + return false; + } +}; + +struct set_premultiplied_visitor +{ + set_premultiplied_visitor(bool status) + : status_(status) {} + + template + void operator() (T & data) + { + data.set_premultiplied(status_); + } + private: + bool status_; +}; + +} // end detail ns + +MAPNIK_DECL bool premultiply_alpha(image_any & image) +{ + return util::apply_visitor(detail::premultiply_visitor(), image); +} + +template +MAPNIK_DECL bool premultiply_alpha(T & image) +{ + detail::premultiply_visitor visit; + return visit(image); +} + +template MAPNIK_DECL bool premultiply_alpha(image_rgba8 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray8 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray8s &); +template MAPNIK_DECL bool premultiply_alpha(image_gray16 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray16s &); +template MAPNIK_DECL bool premultiply_alpha(image_gray32 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray32s &); +template MAPNIK_DECL bool premultiply_alpha(image_gray32f &); +template MAPNIK_DECL bool premultiply_alpha(image_gray64 &); +template MAPNIK_DECL bool premultiply_alpha(image_gray64s &); +template MAPNIK_DECL bool premultiply_alpha(image_gray64f &); + +MAPNIK_DECL bool demultiply_alpha(image_any & image) +{ + return util::apply_visitor(detail::demultiply_visitor(), image); +} + +template +MAPNIK_DECL bool demultiply_alpha(T & image) +{ + detail::demultiply_visitor visit; + return visit(image); +} + +template MAPNIK_DECL bool demultiply_alpha(image_rgba8 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray8 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray8s &); +template MAPNIK_DECL bool demultiply_alpha(image_gray16 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray16s &); +template MAPNIK_DECL bool demultiply_alpha(image_gray32 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray32s &); +template MAPNIK_DECL bool demultiply_alpha(image_gray32f &); +template MAPNIK_DECL bool demultiply_alpha(image_gray64 &); +template MAPNIK_DECL bool demultiply_alpha(image_gray64s &); +template MAPNIK_DECL bool demultiply_alpha(image_gray64f &); + +MAPNIK_DECL void set_premultiplied_alpha(image_any & image, bool status) +{ + util::apply_visitor(detail::set_premultiplied_visitor(status), image); +} + +template +MAPNIK_DECL void set_premultiplied_alpha(T & image, bool status) +{ + detail::set_premultiplied_visitor visit(status); + visit(image); +} + +template MAPNIK_DECL void set_premultiplied_alpha(image_rgba8 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray8 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray8s &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray16 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray16s &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray32 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray32s &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray32f &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray64 &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray64s &, bool); +template MAPNIK_DECL void set_premultiplied_alpha(image_gray64f &, bool); + +namespace detail { + +struct visitor_set_alpha +{ + visitor_set_alpha(float opacity) + : opacity_(opacity) {} + + void operator() (image_rgba8 & data) + { + using pixel_type = image_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) { - surface = cairo_surface_ptr(cairo_ps_surface_create(filename.c_str(),width,height),cairo_surface_closer()); + pixel_type* row_to = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_to[x]; + pixel_type a0 = (rgba >> 24) & 0xff; + pixel_type a1 = pixel_type( ((rgba >> 24) & 0xff) * opacity_ ); + //unsigned a1 = opacity; + if (a0 == a1) continue; + + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + row_to[x] = (a1 << 24)| (b << 16) | (g << 8) | (r) ; + } } -#endif -#ifdef CAIRO_HAS_IMAGE_SURFACE - else if (type == "ARGB32") + } + + template + void operator() (T & data) + { + throw std::runtime_error("Error: set_alpha with " + std::string(typeid(data).name()) + " is not supported"); + } + + private: + float opacity_; + +}; + +} // end detail ns + +MAPNIK_DECL void set_alpha(image_any & data, float opacity) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + util::apply_visitor(detail::visitor_set_alpha(opacity), data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template +MAPNIK_DECL void set_alpha(T & data, float opacity) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + detail::visitor_set_alpha visit(opacity); + visit(data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template MAPNIK_DECL void set_alpha(image_rgba8 &, float); +template MAPNIK_DECL void set_alpha(image_gray8 &, float); +template MAPNIK_DECL void set_alpha(image_gray8s &, float); +template MAPNIK_DECL void set_alpha(image_gray16 &, float); +template MAPNIK_DECL void set_alpha(image_gray16s &, float); +template MAPNIK_DECL void set_alpha(image_gray32 &, float); +template MAPNIK_DECL void set_alpha(image_gray32s &, float); +template MAPNIK_DECL void set_alpha(image_gray32f &, float); +template MAPNIK_DECL void set_alpha(image_gray64 &, float); +template MAPNIK_DECL void set_alpha(image_gray64s &, float); +template MAPNIK_DECL void set_alpha(image_gray64f &, float); + +namespace detail { + +struct visitor_set_grayscale_to_alpha +{ + void operator() (image_rgba8 & data) + { + using pixel_type = image_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) { - surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,width,height),cairo_surface_closer()); + pixel_type* row_from = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + // magic numbers for grayscale + pixel_type a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); + + row_from[x] = (a << 24)| (255 << 16) | (255 << 8) | (255) ; + } } - else if (type == "RGB24") + } + + template + void operator() (T & data) + { + MAPNIK_LOG_WARN(image_util) << "Warning: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported, image was not modified"; + } +}; + +struct visitor_set_grayscale_to_alpha_c +{ + visitor_set_grayscale_to_alpha_c(color const& c) + : c_(c) {} + + void operator() (image_rgba8 & data) + { + using pixel_type = image_rgba8::pixel_type; + for (unsigned int y = 0; y < data.height(); ++y) { - surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_RGB24,width,height),cairo_surface_closer()); + pixel_type* row_from = data.getRow(y); + for (unsigned int x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + + // magic numbers for grayscale + pixel_type a = static_cast(std::ceil((r * .3) + (g * .59) + (b * .11))); + + row_from[x] = (a << 24)| (c_.blue() << 16) | (c_.green() << 8) | (c_.red()) ; + } + } + } + + template + void operator() (T & data) + { + MAPNIK_LOG_WARN(image_util) << "Warning: set_grayscale_to_alpha with " + std::string(typeid(data).name()) + " is not supported, image was not modified"; + } + + private: + color const& c_; +}; + +} // end detail ns + +MAPNIK_DECL void set_grayscale_to_alpha(image_any & data) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + util::apply_visitor(detail::visitor_set_grayscale_to_alpha(), data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template +MAPNIK_DECL void set_grayscale_to_alpha(T & data) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + detail::visitor_set_grayscale_to_alpha visit; + visit(data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template MAPNIK_DECL void set_grayscale_to_alpha(image_rgba8 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray8 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray8s &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray16 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray16s &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32s &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32f &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64 &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64s &); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64f &); + +MAPNIK_DECL void set_grayscale_to_alpha(image_any & data, color const& c) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + util::apply_visitor(detail::visitor_set_grayscale_to_alpha_c(c), data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template +MAPNIK_DECL void set_grayscale_to_alpha(T & data, color const& c) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + detail::visitor_set_grayscale_to_alpha_c visit(c); + visit(data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template MAPNIK_DECL void set_grayscale_to_alpha(image_rgba8 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray8 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray8s &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray16 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray16s &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32s &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray32f &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64 &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64s &, color const&); +template MAPNIK_DECL void set_grayscale_to_alpha(image_gray64f &, color const&); + +namespace detail { + +struct visitor_set_color_to_alpha +{ + visitor_set_color_to_alpha(color const& c) + : c_(c) {} + + void operator() (image_rgba8 & data) + { + using pixel_type = image_rgba8::pixel_type; + for (unsigned y = 0; y < data.height(); ++y) + { + pixel_type* row_from = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + pixel_type rgba = row_from[x]; + pixel_type r = rgba & 0xff; + pixel_type g = (rgba >> 8 ) & 0xff; + pixel_type b = (rgba >> 16) & 0xff; + if (r == c_.red() && g == c_.green() && b == c_.blue()) + { + row_from[x] = 0; + } + } + } + } + + template + void operator() (T & data) + { + throw std::runtime_error("Error: set_color_to_alpha with " + std::string(typeid(data).name()) + " is not supported"); + } + + private: + color const& c_; + +}; + + +} // end detail ns + +MAPNIK_DECL void set_color_to_alpha (image_any & data, color const& c) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + util::apply_visitor(detail::visitor_set_color_to_alpha(c), data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template +MAPNIK_DECL void set_color_to_alpha(T & data, color const& c) +{ + // Prior to calling the data must not be premultiplied + bool remultiply = mapnik::demultiply_alpha(data); + detail::visitor_set_color_to_alpha visit(c); + visit(data); + if (remultiply) + { + mapnik::premultiply_alpha(data); + } +} + +template MAPNIK_DECL void set_color_to_alpha(image_rgba8 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray8 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray8s &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray16 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray16s &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray32 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray32s &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray32f &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray64 &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray64s &, color const&); +template MAPNIK_DECL void set_color_to_alpha(image_gray64f &, color const&); + +namespace detail { + +template +struct visitor_fill +{ + visitor_fill(T1 const& val) + : val_(val) {} + + template + void operator() (T2 & data) + { + using pixel_type = typename T2::pixel_type; + pixel_type val; + try + { + val = numeric_cast(val_); + } + catch(negative_overflow&) + { + val = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + val = std::numeric_limits::max(); + } + data.set(val); + } + + private: + T1 const& val_; +}; + +template<> +struct visitor_fill +{ + visitor_fill(color const& val) + : val_(val) {} + + void operator() (image_rgba8 & data) + { + using pixel_type = image_rgba8::pixel_type; + pixel_type val = static_cast(val_.rgba()); + data.set(val); + data.set_premultiplied(val_.get_premultiplied()); + } + + template + void operator() (T2 & data) + { + using pixel_type = typename T2::pixel_type; + pixel_type val = static_cast(val_.rgba()); + data.set(val); + } + + private: + color const& val_; +}; + +} // end detail ns + +template +MAPNIK_DECL void fill (image_any & data, T const& val) +{ + util::apply_visitor(detail::visitor_fill(val), data); +} + +template MAPNIK_DECL void fill(image_any &, color const&); +template MAPNIK_DECL void fill(image_any &, uint64_t const&); +template MAPNIK_DECL void fill(image_any &, int64_t const&); +template MAPNIK_DECL void fill(image_any &, uint32_t const&); +template MAPNIK_DECL void fill(image_any &, int32_t const&); +template MAPNIK_DECL void fill(image_any &, uint16_t const&); +template MAPNIK_DECL void fill(image_any &, int16_t const&); +template MAPNIK_DECL void fill(image_any &, uint8_t const&); +template MAPNIK_DECL void fill(image_any &, int8_t const&); +template MAPNIK_DECL void fill(image_any &, float const&); +template MAPNIK_DECL void fill(image_any &, double const&); + +template +MAPNIK_DECL void fill (image_rgba8 & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_rgba8 &, color const&); +template MAPNIK_DECL void fill(image_rgba8 &, uint64_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, int64_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, uint32_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, int32_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, uint16_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, int16_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, uint8_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, int8_t const&); +template MAPNIK_DECL void fill(image_rgba8 &, float const&); +template MAPNIK_DECL void fill(image_rgba8 &, double const&); + +template +MAPNIK_DECL void fill (image_gray8 & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray8 &, color const&); +template MAPNIK_DECL void fill(image_gray8 &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray8 &, int64_t const&); +template MAPNIK_DECL void fill(image_gray8 &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray8 &, int32_t const&); +template MAPNIK_DECL void fill(image_gray8 &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray8 &, int16_t const&); +template MAPNIK_DECL void fill(image_gray8 &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray8 &, int8_t const&); +template MAPNIK_DECL void fill(image_gray8 &, float const&); +template MAPNIK_DECL void fill(image_gray8 &, double const&); + +template +MAPNIK_DECL void fill (image_gray8s & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray8s &, color const&); +template MAPNIK_DECL void fill(image_gray8s &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray8s &, int64_t const&); +template MAPNIK_DECL void fill(image_gray8s &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray8s &, int32_t const&); +template MAPNIK_DECL void fill(image_gray8s &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray8s &, int16_t const&); +template MAPNIK_DECL void fill(image_gray8s &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray8s &, int8_t const&); +template MAPNIK_DECL void fill(image_gray8s &, float const&); +template MAPNIK_DECL void fill(image_gray8s &, double const&); + +template +MAPNIK_DECL void fill (image_gray16 & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray16 &, color const&); +template MAPNIK_DECL void fill(image_gray16 &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray16 &, int64_t const&); +template MAPNIK_DECL void fill(image_gray16 &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray16 &, int32_t const&); +template MAPNIK_DECL void fill(image_gray16 &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray16 &, int16_t const&); +template MAPNIK_DECL void fill(image_gray16 &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray16 &, int8_t const&); +template MAPNIK_DECL void fill(image_gray16 &, float const&); +template MAPNIK_DECL void fill(image_gray16 &, double const&); + +template +MAPNIK_DECL void fill (image_gray16s & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray16s &, color const&); +template MAPNIK_DECL void fill(image_gray16s &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray16s &, int64_t const&); +template MAPNIK_DECL void fill(image_gray16s &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray16s &, int32_t const&); +template MAPNIK_DECL void fill(image_gray16s &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray16s &, int16_t const&); +template MAPNIK_DECL void fill(image_gray16s &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray16s &, int8_t const&); +template MAPNIK_DECL void fill(image_gray16s &, float const&); +template MAPNIK_DECL void fill(image_gray16s &, double const&); + +template +MAPNIK_DECL void fill (image_gray32 & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray32 &, color const&); +template MAPNIK_DECL void fill(image_gray32 &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray32 &, int64_t const&); +template MAPNIK_DECL void fill(image_gray32 &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray32 &, int32_t const&); +template MAPNIK_DECL void fill(image_gray32 &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray32 &, int16_t const&); +template MAPNIK_DECL void fill(image_gray32 &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray32 &, int8_t const&); +template MAPNIK_DECL void fill(image_gray32 &, float const&); +template MAPNIK_DECL void fill(image_gray32 &, double const&); + +template +MAPNIK_DECL void fill (image_gray32s & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray32s &, color const&); +template MAPNIK_DECL void fill(image_gray32s &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray32s &, int64_t const&); +template MAPNIK_DECL void fill(image_gray32s &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray32s &, int32_t const&); +template MAPNIK_DECL void fill(image_gray32s &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray32s &, int16_t const&); +template MAPNIK_DECL void fill(image_gray32s &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray32s &, int8_t const&); +template MAPNIK_DECL void fill(image_gray32s &, float const&); +template MAPNIK_DECL void fill(image_gray32s &, double const&); + +template +MAPNIK_DECL void fill (image_gray32f & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray32f &, color const&); +template MAPNIK_DECL void fill(image_gray32f &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray32f &, int64_t const&); +template MAPNIK_DECL void fill(image_gray32f &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray32f &, int32_t const&); +template MAPNIK_DECL void fill(image_gray32f &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray32f &, int16_t const&); +template MAPNIK_DECL void fill(image_gray32f &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray32f &, int8_t const&); +template MAPNIK_DECL void fill(image_gray32f &, float const&); +template MAPNIK_DECL void fill(image_gray32f &, double const&); + +template +MAPNIK_DECL void fill (image_gray64 & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray64 &, color const&); +template MAPNIK_DECL void fill(image_gray64 &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray64 &, int64_t const&); +template MAPNIK_DECL void fill(image_gray64 &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray64 &, int32_t const&); +template MAPNIK_DECL void fill(image_gray64 &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray64 &, int16_t const&); +template MAPNIK_DECL void fill(image_gray64 &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray64 &, int8_t const&); +template MAPNIK_DECL void fill(image_gray64 &, float const&); +template MAPNIK_DECL void fill(image_gray64 &, double const&); + +template +MAPNIK_DECL void fill (image_gray64s & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray64s &, color const&); +template MAPNIK_DECL void fill(image_gray64s &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray64s &, int64_t const&); +template MAPNIK_DECL void fill(image_gray64s &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray64s &, int32_t const&); +template MAPNIK_DECL void fill(image_gray64s &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray64s &, int16_t const&); +template MAPNIK_DECL void fill(image_gray64s &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray64s &, int8_t const&); +template MAPNIK_DECL void fill(image_gray64s &, float const&); +template MAPNIK_DECL void fill(image_gray64s &, double const&); + +template +MAPNIK_DECL void fill (image_gray64f & data, T const& val) +{ + detail::visitor_fill visitor(val); + return visitor(data); +} + +template MAPNIK_DECL void fill(image_gray64f &, color const&); +template MAPNIK_DECL void fill(image_gray64f &, uint64_t const&); +template MAPNIK_DECL void fill(image_gray64f &, int64_t const&); +template MAPNIK_DECL void fill(image_gray64f &, uint32_t const&); +template MAPNIK_DECL void fill(image_gray64f &, int32_t const&); +template MAPNIK_DECL void fill(image_gray64f &, uint16_t const&); +template MAPNIK_DECL void fill(image_gray64f &, int16_t const&); +template MAPNIK_DECL void fill(image_gray64f &, uint8_t const&); +template MAPNIK_DECL void fill(image_gray64f &, int8_t const&); +template MAPNIK_DECL void fill(image_gray64f &, float const&); +template MAPNIK_DECL void fill(image_gray64f &, double const&); + +namespace detail { + +struct visitor_set_rectangle +{ + visitor_set_rectangle(image_any const & src, int x0, int y0) + : src_(src), x0_(x0), y0_(y0) {} + + void operator()(image_rgba8 & dst) + { + using pixel_type = image_rgba8::pixel_type; + image_rgba8 src = util::get(src_); + box2d ext0(0,0,dst.width(),dst.height()); + box2d ext1(x0_,y0_,x0_+src.width(),y0_+src.height()); + + if (ext0.intersects(ext1)) + { + box2d box = ext0.intersect(ext1); + for (std::size_t y = box.miny(); y < box.maxy(); ++y) + { + pixel_type* row_to = dst.getRow(y); + pixel_type const * row_from = src.getRow(y-y0_); + + for (std::size_t x = box.minx(); x < box.maxx(); ++x) + { + if (row_from[x-x0_] & 0xff000000) // Don't change if alpha == 0 + { + row_to[x] = row_from[x-x0_]; + } + } + } + } + } + + void operator() (image_null &) + { + throw std::runtime_error("Set rectangle not support for null images"); + } + + template + void operator() (T & dst) + { + using pixel_type = typename T::pixel_type; + T src = util::get(src_); + box2d ext0(0,0,dst.width(),dst.height()); + box2d ext1(x0_,y0_,x0_+src.width(),y0_+src.height()); + + if (ext0.intersects(ext1)) + { + box2d box = ext0.intersect(ext1); + for (std::size_t y = box.miny(); y < box.maxy(); ++y) + { + pixel_type* row_to = dst.getRow(y); + pixel_type const * row_from = src.getRow(y-y0_); + + for (std::size_t x = box.minx(); x < box.maxx(); ++x) + { + row_to[x] = row_from[x-x0_]; + } + } + } + } + private: + image_any const& src_; + int x0_; + int y0_; +}; + +} // end detail ns + +MAPNIK_DECL void set_rectangle(image_any & dst, image_any const& src, int x, int y) +{ + util::apply_visitor(detail::visitor_set_rectangle(src, x, y), dst); +} + +template +MAPNIK_DECL void set_rectangle (T & dst, T const& src, int x, int y) +{ + detail::visitor_set_rectangle visit(src, x, y); + visit(dst); +} + +template MAPNIK_DECL void set_rectangle(image_rgba8 &, image_rgba8 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray8 &, image_gray8 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray8s &, image_gray8s const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray16 &, image_gray16 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray16s &, image_gray16s const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray32 &, image_gray32 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray32s &, image_gray32s const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray32f &, image_gray32f const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray64 &, image_gray64 const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray64s &, image_gray64s const&, int, int); +template MAPNIK_DECL void set_rectangle(image_gray64f &, image_gray64f const&, int, int); + +namespace detail +{ + +struct visitor_composite_pixel +{ + // Obviously c variable would only work for rgba8 currently, but didn't want to + // make this a template class until new rgba types exist. + visitor_composite_pixel(unsigned op, int x,int y, unsigned c, unsigned cover, double opacity) + : opacity_(opacity), + op_(op), + x_(x), + y_(y), + c_(c), + cover_(cover) {} + + void operator() (image_rgba8 & data) + { + using color_type = agg::rgba8; + using value_type = color_type::value_type; + using order_type = agg::order_rgba; + using blender_type = agg::comp_op_adaptor_rgba; + + if (mapnik::check_bounds(data, x_, y_)) + { + unsigned rgba = data(x_,y_); + unsigned ca = (unsigned)(((c_ >> 24) & 0xff) * opacity_); + unsigned cb = (c_ >> 16 ) & 0xff; + unsigned cg = (c_ >> 8) & 0xff; + unsigned cr = (c_ & 0xff); + blender_type::blend_pix(op_, (value_type*)&rgba, cr, cg, cb, ca, cover_); + data(x_,y_) = rgba; + } + } + + template + void operator() (T & data) + { + throw std::runtime_error("Composite pixel is not supported for this data type"); + } + + private: + double opacity_; + unsigned op_; + int x_; + int y_; + int c_; + unsigned cover_; + +}; + +} // end detail ns + +MAPNIK_DECL void composite_pixel(image_any & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) +{ + util::apply_visitor(detail::visitor_composite_pixel(op, x, y, c, cover, opacity), data); +} + +template +MAPNIK_DECL void composite_pixel(T & data, unsigned op, int x, int y, unsigned c, unsigned cover, double opacity ) +{ + detail::visitor_composite_pixel visitor(op, x, y, c, cover, opacity); + visitor(data); +} + +template MAPNIK_DECL void composite_pixel(image_rgba8 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray8 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray8s &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray16 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray16s &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray32 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray32s &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray32f &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray64 &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray64s &, unsigned, int, int, unsigned, unsigned, double); +template MAPNIK_DECL void composite_pixel(image_gray64f &, unsigned, int, int, unsigned, unsigned, double); + +namespace detail { + +template +struct visitor_set_pixel +{ + visitor_set_pixel(std::size_t x, std::size_t y, T1 const& val) + : val_(val), x_(x), y_(y) {} + + template + void operator() (T2 & data) + { + using pixel_type = typename T2::pixel_type; + pixel_type val; + try + { + val = numeric_cast(val_); + } + catch(negative_overflow&) + { + val = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + val = std::numeric_limits::max(); + } + if (check_bounds(data, x_, y_)) + { + data(x_, y_) = val; + } + } + + private: + T1 const& val_; + std::size_t x_; + std::size_t y_; +}; + +template<> +struct visitor_set_pixel +{ + visitor_set_pixel(std::size_t x, std::size_t y, color const& val) + : val_(val), x_(x), y_(y) {} + + template + void operator() (T2 & data) + { + using pixel_type = typename T2::pixel_type; + pixel_type val; + if (data.get_premultiplied() && !val_.get_premultiplied()) + { + color tmp(val_); + tmp.premultiply(); + val = static_cast(tmp.rgba()); + } + else if (!data.get_premultiplied() && val_.get_premultiplied()) + { + color tmp(val_); + tmp.demultiply(); + val = static_cast(tmp.rgba()); } -#endif else { - throw ImageWriterException("unknown file type: " + type); + val = static_cast(val_.rgba()); } - - //cairo_t * ctx = cairo_create(surface); - - // TODO - expose as user option - /* - if (type == "ARGB32" || type == "RGB24") - { - context->set_antialias(Cairo::ANTIALIAS_NONE); - } - */ - - mapnik::cairo_renderer ren(map, create_context(surface), scale_factor); - ren.apply(scale_denominator); - - if (type == "ARGB32" || type == "RGB24") + if (check_bounds(data, x_, y_)) { - cairo_surface_write_to_png(&*surface, filename.c_str()); + data(x_, y_) = val; } - cairo_surface_finish(&*surface); } + + private: + color const& val_; + std::size_t x_; + std::size_t y_; +}; + +} // end detail ns + +template +MAPNIK_DECL void set_pixel (image_any & data, std::size_t x, std::size_t y, T const& val) +{ + util::apply_visitor(detail::visitor_set_pixel(x, y, val), data); } +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_any &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_rgba8 & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_rgba8 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray8 & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray8 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray8s & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray8s &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray16 & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray16 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray16s & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray16s &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray32 & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray32 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray32s & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray32s &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray32f & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray32f &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray64 & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray64 &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray64s & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray64s &, std::size_t, std::size_t, double const&); + +template +MAPNIK_DECL void set_pixel (image_gray64f & data, std::size_t x, std::size_t y, T const& val) +{ + detail::visitor_set_pixel visitor(x, y, val); + visitor(data); +} + +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, color const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, uint64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, int64_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, uint32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, int32_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, uint16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, int16_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, uint8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, int8_t const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, float const&); +template MAPNIK_DECL void set_pixel(image_gray64f &, std::size_t, std::size_t, double const&); + +namespace detail { + +template +struct visitor_get_pixel +{ + visitor_get_pixel(std::size_t x, std::size_t y) + : x_(x), y_(y) {} + + template + T1 operator() (T2 const& data) + { + if (check_bounds(data, x_, y_)) + { + T1 val; + try + { + val = numeric_cast(data(x_,y_)); + } + catch(negative_overflow&) + { + val = std::numeric_limits::min(); + } + catch(positive_overflow&) + { + val = std::numeric_limits::max(); + } + return val; + } + else + { + throw std::runtime_error("Out of range for dataset with get pixel"); + } + } + + private: + std::size_t x_; + std::size_t y_; +}; + +template<> +struct visitor_get_pixel +{ + visitor_get_pixel(std::size_t x, std::size_t y) + : x_(x), y_(y) {} + + template + color operator() (T2 const& data) + { + if (check_bounds(data, x_, y_)) + { + return color(static_cast(data(x_, y_)), data.get_premultiplied()); + } + else + { + throw std::runtime_error("Out of range for dataset with get pixel"); + } + } + + private: + std::size_t x_; + std::size_t y_; +}; + +} // end detail ns + +template +MAPNIK_DECL T get_pixel (image_any const& data, std::size_t x, std::size_t y) +{ + return util::apply_visitor(detail::visitor_get_pixel(x, y), data); +} + +template MAPNIK_DECL color get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_any const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_any const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_any const& data, std::size_t x, std::size_t y) +{ + return util::apply_visitor(detail::visitor_get_pixel(x, y), data); +} + +template MAPNIK_DECL color get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_any const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_any const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_rgba8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_rgba8 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray8 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray8s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray8s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray16 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray16 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray16s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray16s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray32 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray32 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray32s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray32s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray32f const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray32f const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray64 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray64 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray64s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray64s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_gray64f const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_gray64f const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_rgba8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_rgba8 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray8 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray8 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray8 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray8s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray8s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray8s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray16 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray16 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray16 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray16s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray16s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray16s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray32 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray32 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray32 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray32s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray32s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray32s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray32f const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray32f const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray32f const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray64 const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray64 const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray64 const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray64s const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray64s const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray64s const&, std::size_t, std::size_t); + +template +MAPNIK_DECL T get_pixel (image_view_gray64f const& data, std::size_t x, std::size_t y) +{ + detail::visitor_get_pixel visitor(x, y); + return visitor(data); +} + +template MAPNIK_DECL color get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint64_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int64_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint32_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int32_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint16_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int16_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL uint8_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL int8_t get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL float get_pixel(image_view_gray64f const&, std::size_t, std::size_t); +template MAPNIK_DECL double get_pixel(image_view_gray64f const&, std::size_t, std::size_t); + +namespace detail +{ + +struct visitor_view_to_string +{ + visitor_view_to_string(std::ostringstream & ss) + : ss_(ss) {} + + template + void operator() (T const& view) + { + for (std::size_t i=0;i(view.getRow(i)), + view.getRowSize()); + } + } + + private: + std::ostringstream & ss_; +}; + +} // end detail ns + + +MAPNIK_DECL void view_to_string (image_view_any const& view, std::ostringstream & ss) +{ + util::apply_visitor(detail::visitor_view_to_string(ss), view); +} + +namespace detail +{ + +struct visitor_create_view +{ + visitor_create_view(unsigned x,unsigned y, unsigned w, unsigned h) + : x_(x), y_(y), w_(w), h_(h) {} + + image_view_any operator() (image_null const&) + { + throw std::runtime_error("Can not make a view from a null image"); + } + + template + image_view_any operator() (T const& data) + { + image_view view(x_,y_,w_,h_,data); + return image_view_any(view); + } + private: + unsigned x_; + unsigned y_; + unsigned w_; + unsigned h_; +}; + +} // end detail ns + +MAPNIK_DECL image_view_any create_view(image_any const& data,unsigned x,unsigned y, unsigned w,unsigned h) +{ + return util::apply_visitor(detail::visitor_create_view(x,y,w,h), data); +} + +template +MAPNIK_DECL unsigned compare(T const& im1, T const& im2, double threshold, bool) +{ + using pixel_type = typename T::pixel_type; + if (im1.width() != im2.width() || im1.height() != im2.height()) + { + return im1.width() * im1.height(); + } + unsigned difference = 0; + for (unsigned int y = 0; y < im1.height(); ++y) + { + const pixel_type * row_from = im1.getRow(y); + const pixel_type * row_from2 = im2.getRow(y); + for (unsigned int x = 0; x < im1.width(); ++x) + { + double d = std::abs(static_cast(row_from[x]) - static_cast(row_from2[x])); + if (d > threshold) + { + ++difference; + } + } + } + return difference; +} + +template MAPNIK_DECL unsigned compare(image_gray8 const&, image_gray8 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray8s const&, image_gray8s const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray16 const&, image_gray16 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray16s const&, image_gray16s const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray32 const&, image_gray32 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray32s const&, image_gray32s const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray32f const&, image_gray32f const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray64 const&, image_gray64 const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray64s const&, image_gray64s const&, double, bool); +template MAPNIK_DECL unsigned compare(image_gray64f const&, image_gray64f const&, double, bool); + +template <> +MAPNIK_DECL unsigned compare(image_null const&, image_null const&, double, bool) +{ + return 0; +} + +template <> +MAPNIK_DECL unsigned compare(image_rgba8 const& im1, image_rgba8 const& im2, double threshold, bool alpha) +{ + using pixel_type = image_rgba8::pixel_type; + if (im1.width() != im2.width() || im1.height() != im2.height()) + { + return im1.width() * im1.height(); + } + unsigned difference = 0; +#ifdef SSE_MATH + __m128i true_set = _mm_set1_epi8(0xff); + __m128i one = _mm_set1_epi32(1); + __m128i sum = _mm_setzero_si128(); + uint32_t alphamask = 0xffffffff; + if (!alpha) + { + alphamask = 0xffffff; + } + __m128i mask = _mm_set1_epi32(alphamask); + if (threshold == 0.0) + { + for (unsigned int y = 0; y < im1.height(); ++y) + { + const std::uint32_t * row_from = im1.getRow(y); + const std::uint32_t * row_from2 = im2.getRow(y); + int x = 0; + for (; x < ROUND_DOWN(im1.width(),4); x +=4 ) + { + __m128i rgba = _mm_loadu_si128((__m128i*)(row_from + x)); + __m128i rgba2 = _mm_loadu_si128((__m128i*)(row_from2 + x)); + rgba = _mm_and_si128(rgba, mask); + rgba2 = _mm_and_si128(rgba2, mask); + __m128i eq = _mm_cmpeq_epi8(rgba,rgba2); + __m128i comp2 = _mm_cmpeq_epi32(eq, true_set); + sum = _mm_add_epi32(sum, _mm_andnot_si128(comp2, one)); + } + for (; x < im1.width(); ++x) + { + if ((row_from[x] & alphamask) != (row_from2[x] & alphamask)) + { + ++difference; + } + } + } + m128_int diff_sum; + diff_sum.v = sum; + difference += diff_sum.u32[0]; + difference += diff_sum.u32[1]; + difference += diff_sum.u32[2]; + difference += diff_sum.u32[3]; + } + else + { + uint8_t thres = static_cast(threshold); + __m128i m_thres = _mm_set1_epi8(thres); + for (unsigned int y = 0; y < im1.height(); ++y) + { + const std::uint32_t * row_from = im1.getRow(y); + const std::uint32_t * row_from2 = im2.getRow(y); + int x = 0; + for (; x < ROUND_DOWN(im1.width(),4); x +=4 ) + { + __m128i rgba = _mm_loadu_si128((__m128i*)(row_from + x)); + __m128i rgba2 = _mm_loadu_si128((__m128i*)(row_from2 + x)); + rgba = _mm_and_si128(rgba, mask); + rgba2 = _mm_and_si128(rgba2, mask); + __m128i abs = _mm_absdiff_epu8(rgba, rgba2); + __m128i compare = _mm_cmpgt_epu8(abs, m_thres); + __m128i comp2 = _mm_cmpeq_epi32(compare, _mm_setzero_si128()); + sum = _mm_add_epi32(sum, _mm_andnot_si128(comp2, one)); + } + for (; x < im1.width(); ++x) + { + unsigned rgba = row_from[x]; + unsigned rgba2 = row_from2[x]; + unsigned r = rgba & 0xff; + unsigned g = (rgba >> 8 ) & 0xff; + unsigned b = (rgba >> 16) & 0xff; + unsigned r2 = rgba2 & 0xff; + unsigned g2 = (rgba2 >> 8 ) & 0xff; + unsigned b2 = (rgba2 >> 16) & 0xff; + if (std::abs(static_cast(r - r2)) > static_cast(threshold) || + std::abs(static_cast(g - g2)) > static_cast(threshold) || + std::abs(static_cast(b - b2)) > static_cast(threshold)) { + ++difference; + continue; + } + if (alpha) { + unsigned a = (rgba >> 24) & 0xff; + unsigned a2 = (rgba2 >> 24) & 0xff; + if (std::abs(static_cast(a - a2)) > static_cast(threshold)) { + ++difference; + continue; + } + } + } + } + m128_int diff_sum; + diff_sum.v = sum; + difference += diff_sum.u32[0]; + difference += diff_sum.u32[1]; + difference += diff_sum.u32[2]; + difference += diff_sum.u32[3]; + } +#else + for (unsigned int y = 0; y < im1.height(); ++y) + { + const std::uint32_t * row_from = im1.getRow(y); + const std::uint32_t * row_from2 = im2.getRow(y); + for (unsigned int x = 0; x < im1.width(); ++x) + { + unsigned rgba = row_from[x]; + unsigned rgba2 = row_from2[x]; + unsigned r = rgba & 0xff; + unsigned g = (rgba >> 8 ) & 0xff; + unsigned b = (rgba >> 16) & 0xff; + unsigned r2 = rgba2 & 0xff; + unsigned g2 = (rgba2 >> 8 ) & 0xff; + unsigned b2 = (rgba2 >> 16) & 0xff; + if (std::abs(static_cast(r - r2)) > static_cast(threshold) || + std::abs(static_cast(g - g2)) > static_cast(threshold) || + std::abs(static_cast(b - b2)) > static_cast(threshold)) { + ++difference; + continue; + } + if (alpha) { + unsigned a = (rgba >> 24) & 0xff; + unsigned a2 = (rgba2 >> 24) & 0xff; + if (std::abs(static_cast(a - a2)) > static_cast(threshold)) { + ++difference; + continue; + } + } + } + } #endif - -template void save_to_file(image_data_rgba8 const&, - std::string const&, - std::string const&); - -template void save_to_file(image_data_rgba8 const&, - std::string const&, - std::string const&, - rgba_palette const& palette); - -template void save_to_file(image_data_rgba8 const&, - std::string const&); - -template void save_to_file(image_data_rgba8 const&, - std::string const&, - rgba_palette const& palette); - -template std::string save_to_string(image_data_rgba8 const&, - std::string const&); - -template std::string save_to_string(image_data_rgba8 const&, - std::string const&, - rgba_palette const& palette); - -template void save_to_file > (image_view const&, - std::string const&, - std::string const&); - -template void save_to_file > (image_view const&, - std::string const&, - std::string const&, - rgba_palette const& palette); - -template void save_to_file > (image_view const&, - std::string const&); - -template void save_to_file > (image_view const&, - std::string const&, - rgba_palette const& palette); - -template std::string save_to_string > (image_view const&, - std::string const&); - -template std::string save_to_string > (image_view const&, - std::string const&, - rgba_palette const& palette); - + return difference; } + +namespace detail +{ + +struct visitor_compare +{ + visitor_compare(image_any const& im2, double threshold, bool alpha) + : im2_(im2), threshold_(threshold), alpha_(alpha) {} + + template + unsigned operator() (T const & im1) + { + if (!im2_.is()) + { + return im1.width() * im1.height(); + } + return mapnik::compare(im1, util::get(im2_), threshold_, alpha_); + } + + private: + image_any const& im2_; + double threshold_; + bool alpha_; +}; + +} // end detail ns + +template <> +MAPNIK_DECL unsigned compare(image_any const& im1, image_any const& im2, double threshold, bool alpha) +{ + return util::apply_visitor(detail::visitor_compare(im2, threshold, alpha), im1); +} + +} // end ns diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp new file mode 100644 index 000000000..b6da08f76 --- /dev/null +++ b/src/image_util_jpeg.cpp @@ -0,0 +1,114 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +#if defined(HAVE_JPEG) +#include +#endif + +#include +#include +#include +#include +#include +#include + +// boost +#include + +// stl +#include +#include + +namespace mapnik +{ + +jpeg_saver::jpeg_saver(std::ostream & stream, std::string const& t): + stream_(stream), t_(t) {} + +template +void process_rgba8_jpeg(T const& image, std::string const& t, std::ostream & stream) +{ +#if defined(HAVE_JPEG) + int quality = 85; + std::string val = t.substr(4); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,quality) || quality < 0 || quality > 100) + { + throw ImageWriterException("invalid jpeg quality: '" + val + "'"); + } + } + save_as_jpeg(stream, quality, image); +#else + throw ImageWriterException("jpeg output is not enabled in your build of Mapnik"); +#endif +} + +template<> +void jpeg_saver::operator() (image_rgba8 const& image) const +{ + process_rgba8_jpeg(image, t_, stream_); +} + +template<> +void jpeg_saver::operator() (image_view_rgba8 const& image) const +{ + process_rgba8_jpeg(image, t_, stream_); +} + +template<> +void jpeg_saver::operator() (image_null const& image) const +{ + throw ImageWriterException("Can not save a null image to jpeg"); +} + +template +void jpeg_saver::operator() (T const& image) const +{ + throw ImageWriterException("Mapnik does not support jpeg grayscale images"); +} + +template void jpeg_saver::operator() (image_rgba8 const& image) const; +template void jpeg_saver::operator() (image_gray8 const& image) const; +template void jpeg_saver::operator() (image_gray8s const& image) const; +template void jpeg_saver::operator() (image_gray16 const& image) const; +template void jpeg_saver::operator() (image_gray16s const& image) const; +template void jpeg_saver::operator() (image_gray32 const& image) const; +template void jpeg_saver::operator() (image_gray32s const& image) const; +template void jpeg_saver::operator() (image_gray32f const& image) const; +template void jpeg_saver::operator() (image_gray64 const& image) const; +template void jpeg_saver::operator() (image_gray64s const& image) const; +template void jpeg_saver::operator() (image_gray64f const& image) const; +template void jpeg_saver::operator() (image_view_rgba8 const& image) const; +template void jpeg_saver::operator() (image_view_gray8 const& image) const; +template void jpeg_saver::operator() (image_view_gray8s const& image) const; +template void jpeg_saver::operator() (image_view_gray16 const& image) const; +template void jpeg_saver::operator() (image_view_gray16s const& image) const; +template void jpeg_saver::operator() (image_view_gray32 const& image) const; +template void jpeg_saver::operator() (image_view_gray32s const& image) const; +template void jpeg_saver::operator() (image_view_gray32f const& image) const; +template void jpeg_saver::operator() (image_view_gray64 const& image) const; +template void jpeg_saver::operator() (image_view_gray64s const& image) const; +template void jpeg_saver::operator() (image_view_gray64f const& image) const; + +} // end ns diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp new file mode 100644 index 000000000..68b2b66df --- /dev/null +++ b/src/image_util_png.cpp @@ -0,0 +1,356 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 + * + *****************************************************************************/ + +#if defined(HAVE_PNG) +extern "C" +{ +#include +} +#endif + +// mapnik +#if defined(HAVE_PNG) +#include +#endif + +#include +#include +#include +#include +#include +#include + +// boost +#include + +// stl +#include +#include + +namespace mapnik +{ + +#if defined(HAVE_PNG) + +void handle_png_options(std::string const& type, + png_options & opts) +{ + if (type == "png" || type == "png24" || type == "png32") + { + opts.paletted = false; + return; + } + else if (type == "png8" || type == "png256") + { + opts.paletted = true; + return; + } + boost::char_separator sep(":"); + boost::tokenizer< boost::char_separator > tokens(type, sep); + bool set_colors = false; + bool set_gamma = false; + for (std::string const& t : tokens) + { + if (t == "png8" || t == "png256") + { + opts.paletted = true; + } + else if (t == "png" || t == "png24" || t == "png32") + { + opts.paletted = false; + } + else if (t == "m=o") + { + opts.use_hextree = false; + } + else if (t == "m=h") + { + opts.use_hextree = true; + } + else if (t == "e=miniz") + { + opts.use_miniz = true; + } + else if (boost::algorithm::starts_with(t, "c=")) + { + set_colors = true; + if (!mapnik::util::string2int(t.substr(2),opts.colors) || opts.colors < 1 || opts.colors > 256) + { + throw ImageWriterException("invalid color parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "t=")) + { + if (!mapnik::util::string2int(t.substr(2),opts.trans_mode) || opts.trans_mode < 0 || opts.trans_mode > 2) + { + throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "g=")) + { + set_gamma = true; + if (!mapnik::util::string2double(t.substr(2),opts.gamma) || opts.gamma < 0) + { + throw ImageWriterException("invalid gamma parameter: " + t.substr(2)); + } + } + else if (boost::algorithm::starts_with(t, "z=")) + { + /* + #define Z_NO_COMPRESSION 0 + #define Z_BEST_SPEED 1 + #define Z_BEST_COMPRESSION 9 + #define Z_DEFAULT_COMPRESSION (-1) + */ + if (!mapnik::util::string2int(t.substr(2),opts.compression) + || opts.compression < Z_DEFAULT_COMPRESSION + || opts.compression > 10) // use 10 here rather than Z_BEST_COMPRESSION (9) to allow for MZ_UBER_COMPRESSION + { + throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 10 are valid)"); + } + } + else if (boost::algorithm::starts_with(t, "s=")) + { + std::string s = t.substr(2); + if (s == "default") + { + opts.strategy = Z_DEFAULT_STRATEGY; + } + else if (s == "filtered") + { + opts.strategy = Z_FILTERED; + } + else if (s == "huff") + { + opts.strategy = Z_HUFFMAN_ONLY; + } + else if (s == "rle") + { + opts.strategy = Z_RLE; + } + else if (s == "fixed") + { + opts.strategy = Z_FIXED; + } + else + { + throw ImageWriterException("invalid compression strategy parameter: " + s); + } + } + else + { + throw ImageWriterException("unhandled png option: " + t); + } + } + // validation + if (!opts.paletted && set_colors) + { + throw ImageWriterException("invalid color parameter: unavailable for true color (non-paletted) images"); + } + if (!opts.paletted && set_gamma) + { + throw ImageWriterException("invalid gamma parameter: unavailable for true color (non-paletted) images"); + } + if ((opts.use_miniz == false) && opts.compression > Z_BEST_COMPRESSION) + { + throw ImageWriterException("invalid compression value: (only -1 through 9 are valid)"); + } +} +#endif + +png_saver::png_saver(std::ostream & stream, std::string const& t): + stream_(stream), t_(t) {} + +png_saver_pal::png_saver_pal(std::ostream & stream, std::string const& t, rgba_palette const& pal): + stream_(stream), t_(t), pal_(pal) {} + +template<> +void png_saver::operator() (image_null const& image) const +{ + throw ImageWriterException("null images not supported for png"); +} + +template<> +void png_saver_pal::operator() (image_null const& image) const +{ + throw ImageWriterException("null images not supported for png"); +} + +template +void process_rgba8_png_pal(T const& image, + std::string const& t, + std::ostream & stream, + rgba_palette const& pal) +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(t, opts); + if (pal.valid()) + { + png_options opts; + handle_png_options(t,opts); + save_as_png8_pal(stream, image, pal, opts); + } + else if (opts.paletted) + { + if (opts.use_hextree) + { + save_as_png8_hex(stream, image, opts); + } + else + { + save_as_png8_oct(stream, image, opts); + } + } + else + { + save_as_png(stream, image, opts); + } +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +template +void process_rgba8_png(T const& image, + std::string const& t, + std::ostream & stream) +{ +#if defined(HAVE_PNG) + png_options opts; + handle_png_options(t, opts); + if (opts.paletted) + { + if (opts.use_hextree) + { + save_as_png8_hex(stream, image, opts); + } + else + { + save_as_png8_oct(stream, image, opts); + } + } + else + { + save_as_png(stream, image, opts); + } +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +template<> +void png_saver_pal::operator() (image_rgba8 const& image) const +{ + process_rgba8_png_pal(image, t_, stream_, pal_); +} + +template<> +void png_saver_pal::operator() (image_view_rgba8 const& image) const +{ + process_rgba8_png_pal(image, t_, stream_, pal_); +} + +template<> +void png_saver::operator() (image_rgba8 const& image) const +{ + process_rgba8_png(image, t_, stream_); +} + +template<> +void png_saver::operator() (image_view_rgba8 const& image) const +{ + process_rgba8_png(image, t_, stream_); +} + +template +void png_saver::operator() (T const& image) const +{ +#if defined(HAVE_PNG) + throw ImageWriterException("Mapnik does not support grayscale images for png"); + //png_options opts; + //handle_png_options(t_, opts); + //save_as_png(stream_, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +template +void png_saver_pal::operator() (T const& image) const +{ +#if defined(HAVE_PNG) + throw ImageWriterException("Mapnik does not support grayscale images for png"); + //png_options opts; + //handle_png_options(t_, opts); + //save_as_png(stream_, image, opts); +#else + throw ImageWriterException("png output is not enabled in your build of Mapnik"); +#endif +} + +template void png_saver::operator() (image_rgba8 const& image) const; +template void png_saver::operator() (image_gray8 const& image) const; +template void png_saver::operator() (image_gray8s const& image) const; +template void png_saver::operator() (image_gray16 const& image) const; +template void png_saver::operator() (image_gray16s const& image) const; +template void png_saver::operator() (image_gray32 const& image) const; +template void png_saver::operator() (image_gray32s const& image) const; +template void png_saver::operator() (image_gray32f const& image) const; +template void png_saver::operator() (image_gray64 const& image) const; +template void png_saver::operator() (image_gray64s const& image) const; +template void png_saver::operator() (image_gray64f const& image) const; +template void png_saver::operator() (image_view_rgba8 const& image) const; +template void png_saver::operator() (image_view_gray8 const& image) const; +template void png_saver::operator() (image_view_gray8s const& image) const; +template void png_saver::operator() (image_view_gray16 const& image) const; +template void png_saver::operator() (image_view_gray16s const& image) const; +template void png_saver::operator() (image_view_gray32 const& image) const; +template void png_saver::operator() (image_view_gray32s const& image) const; +template void png_saver::operator() (image_view_gray32f const& image) const; +template void png_saver::operator() (image_view_gray64 const& image) const; +template void png_saver::operator() (image_view_gray64s const& image) const; +template void png_saver::operator() (image_view_gray64f const& image) const; +template void png_saver_pal::operator() (image_rgba8 const& image) const; +template void png_saver_pal::operator() (image_gray8 const& image) const; +template void png_saver_pal::operator() (image_gray8s const& image) const; +template void png_saver_pal::operator() (image_gray16 const& image) const; +template void png_saver_pal::operator() (image_gray16s const& image) const; +template void png_saver_pal::operator() (image_gray32 const& image) const; +template void png_saver_pal::operator() (image_gray32s const& image) const; +template void png_saver_pal::operator() (image_gray32f const& image) const; +template void png_saver_pal::operator() (image_gray64 const& image) const; +template void png_saver_pal::operator() (image_gray64s const& image) const; +template void png_saver_pal::operator() (image_gray64f const& image) const; +template void png_saver_pal::operator() (image_view_rgba8 const& image) const; +template void png_saver_pal::operator() (image_view_gray8 const& image) const; +template void png_saver_pal::operator() (image_view_gray8s const& image) const; +template void png_saver_pal::operator() (image_view_gray16 const& image) const; +template void png_saver_pal::operator() (image_view_gray16s const& image) const; +template void png_saver_pal::operator() (image_view_gray32 const& image) const; +template void png_saver_pal::operator() (image_view_gray32s const& image) const; +template void png_saver_pal::operator() (image_view_gray32f const& image) const; +template void png_saver_pal::operator() (image_view_gray64 const& image) const; +template void png_saver_pal::operator() (image_view_gray64s const& image) const; +template void png_saver_pal::operator() (image_view_gray64f const& image) const; + +} // end ns diff --git a/src/image_util_tiff.cpp b/src/image_util_tiff.cpp new file mode 100644 index 000000000..22f1924f1 --- /dev/null +++ b/src/image_util_tiff.cpp @@ -0,0 +1,207 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +#if defined(HAVE_TIFF) +#include +#endif + +#include +#include +#include +#include +#include + +// boost +#include + +// stl +#include + +namespace mapnik +{ + +#if defined(HAVE_TIFF) +void handle_tiff_options(std::string const& type, + tiff_config & config) +{ + if (type == "tiff") + { + return; + } + if (type.length() > 4) + { + boost::char_separator sep(":"); + boost::tokenizer< boost::char_separator > tokens(type, sep); + for (auto const& t : tokens) + { + if (t == "tiff") + { + continue; + } + else if (boost::algorithm::starts_with(t, "compression=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + if (val == "deflate") + { + config.compression = COMPRESSION_DEFLATE; + } + else if (val == "adobedeflate") + { + config.compression = COMPRESSION_ADOBE_DEFLATE; + } + else if (val == "lzw") + { + config.compression = COMPRESSION_LZW; + } + else if (val == "none") + { + config.compression = COMPRESSION_NONE; + } + else + { + throw ImageWriterException("invalid tiff compression: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "method=")) + { + std::string val = t.substr(7); + if (!val.empty()) + { + if (val == "scanline") + { + config.method = TIFF_WRITE_SCANLINE; + } + else if (val == "strip" || val == "stripped") + { + config.method = TIFF_WRITE_STRIPPED; + } + else if (val == "tiled") + { + config.method = TIFF_WRITE_TILED; + } + else + { + throw ImageWriterException("invalid tiff method: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "zlevel=")) + { + std::string val = t.substr(7); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.zlevel) || config.zlevel < 0 || config.zlevel > 9) + { + throw ImageWriterException("invalid tiff zlevel: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "tile_height=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.tile_height) || config.tile_height < 0 ) + { + throw ImageWriterException("invalid tiff tile_height: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "tile_width=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.tile_width) || config.tile_width < 0 ) + { + throw ImageWriterException("invalid tiff tile_width: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "rows_per_strip=")) + { + std::string val = t.substr(15); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.rows_per_strip) || config.rows_per_strip < 0 ) + { + throw ImageWriterException("invalid tiff rows_per_strip: '" + val + "'"); + } + } + } + else + { + throw ImageWriterException("unhandled tiff option: " + t); + } + } + } +} +#endif + +tiff_saver::tiff_saver(std::ostream & stream, std::string const& t): + stream_(stream), t_(t) {} +template<> +void tiff_saver::operator() (image_null const& image) const +{ + throw ImageWriterException("null images not supported"); +} + +template +void tiff_saver::operator() (T const& image) const +{ +#if defined(HAVE_TIFF) + tiff_config opts; + handle_tiff_options(t_, opts); + save_as_tiff(stream_, image, opts); +#else + throw ImageWriterException("tiff output is not enabled in your build of Mapnik"); +#endif +} + +template void tiff_saver::operator() (image_rgba8 const& image) const; +template void tiff_saver::operator() (image_gray8 const& image) const; +template void tiff_saver::operator() (image_gray8s const& image) const; +template void tiff_saver::operator() (image_gray16 const& image) const; +template void tiff_saver::operator() (image_gray16s const& image) const; +template void tiff_saver::operator() (image_gray32 const& image) const; +template void tiff_saver::operator() (image_gray32s const& image) const; +template void tiff_saver::operator() (image_gray32f const& image) const; +template void tiff_saver::operator() (image_gray64 const& image) const; +template void tiff_saver::operator() (image_gray64s const& image) const; +template void tiff_saver::operator() (image_gray64f const& image) const; +template void tiff_saver::operator() (image_view_rgba8 const& image) const; +template void tiff_saver::operator() (image_view_gray8 const& image) const; +template void tiff_saver::operator() (image_view_gray8s const& image) const; +template void tiff_saver::operator() (image_view_gray16 const& image) const; +template void tiff_saver::operator() (image_view_gray16s const& image) const; +template void tiff_saver::operator() (image_view_gray32 const& image) const; +template void tiff_saver::operator() (image_view_gray32s const& image) const; +template void tiff_saver::operator() (image_view_gray32f const& image) const; +template void tiff_saver::operator() (image_view_gray64 const& image) const; +template void tiff_saver::operator() (image_view_gray64s const& image) const; +template void tiff_saver::operator() (image_view_gray64f const& image) const; + +} // end ns diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp new file mode 100644 index 000000000..836039e40 --- /dev/null +++ b/src/image_util_webp.cpp @@ -0,0 +1,403 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2014 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 +#if defined(HAVE_WEBP) +#include +#endif + +#include +#include +#include +#include +#include +#include + +// boost +#include + +// stl +#include +#include + +namespace mapnik +{ + +#if defined(HAVE_WEBP) +void handle_webp_options(std::string const& type, + WebPConfig & config, + bool & alpha) +{ + if (type == "webp") + { + return; + } + if (type.length() > 4){ + boost::char_separator sep(":"); + boost::tokenizer< boost::char_separator > tokens(type, sep); + for (auto const& t : tokens) + { + if (t == "webp") + { + continue; + } + else if (boost::algorithm::starts_with(t, "quality=")) + { + std::string val = t.substr(8); + if (!val.empty()) + { + double quality = 90; + if (!mapnik::util::string2double(val,quality) || quality < 0.0 || quality > 100.0) + { + throw ImageWriterException("invalid webp quality: '" + val + "'"); + } + config.quality = static_cast(quality); + } + } + else if (boost::algorithm::starts_with(t, "method=")) + { + std::string val = t.substr(7); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.method) || config.method < 0 || config.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 (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 + if (!mapnik::util::string2int(val,config.lossless) || config.lossless < 0 || config.lossless > 1) + { + throw ImageWriterException("invalid webp lossless: '" + val + "'"); + } + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support the lossless flag) + #else + #warning "compiling against webp that does not support the lossless flag" + #endif + throw ImageWriterException("your webp version does not support the lossless option"); + #endif + } + } + else if (boost::algorithm::starts_with(t, "image_hint=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 + int image_hint = 0; + if (!mapnik::util::string2int(val,image_hint) || image_hint < 0 || image_hint > 3) + { + throw ImageWriterException("invalid webp image_hint: '" + val + "'"); + } + config.image_hint = static_cast(image_hint); + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support the image_hint flag) + #else + #warning "compiling against webp that does not support the image_hint flag" + #endif + throw ImageWriterException("your webp version does not support the image_hint option"); + #endif + } + } + else if (boost::algorithm::starts_with(t, "alpha=")) + { + std::string val = t.substr(6); + if (!val.empty()) + { + if (!mapnik::util::string2bool(val,alpha)) + { + throw ImageWriterException("invalid webp alpha: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "target_size=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.target_size)) + { + throw ImageWriterException("invalid webp target_size: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "target_psnr=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + double psnr = 0; + if (!mapnik::util::string2double(val,psnr)) + { + throw ImageWriterException("invalid webp target_psnr: '" + val + "'"); + } + config.target_PSNR = psnr; + } + } + else if (boost::algorithm::starts_with(t, "segments=")) + { + std::string val = t.substr(9); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.segments)) + { + throw ImageWriterException("invalid webp segments: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "sns_strength=")) + { + std::string val = t.substr(13); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.sns_strength)) + { + throw ImageWriterException("invalid webp sns_strength: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "filter_strength=")) + { + std::string val = t.substr(16); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.filter_strength)) + { + throw ImageWriterException("invalid webp filter_strength: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "filter_sharpness=")) + { + std::string val = t.substr(17); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.filter_sharpness)) + { + throw ImageWriterException("invalid webp filter_sharpness: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "filter_type=")) + { + std::string val = t.substr(12); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.filter_type)) + { + throw ImageWriterException("invalid webp filter_type: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "autofilter=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.autofilter)) + { + throw ImageWriterException("invalid webp autofilter: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "alpha_compression=")) + { + std::string val = t.substr(18); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.alpha_compression)) + { + throw ImageWriterException("invalid webp alpha_compression: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "alpha_filtering=")) + { + std::string val = t.substr(16); + if (!val.empty()) + { + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 + if (!mapnik::util::string2int(val,config.alpha_filtering)) + { + throw ImageWriterException("invalid webp alpha_filtering: '" + val + "'"); + } + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support the alpha_filtering flag) + #else + #warning "compiling against webp that does not support the alpha_filtering flag" + #endif + throw ImageWriterException("your webp version does not support the alpha_filtering option"); + #endif + } + } + else if (boost::algorithm::starts_with(t, "alpha_quality=")) + { + std::string val = t.substr(14); + if (!val.empty()) + { + #if (WEBP_ENCODER_ABI_VERSION >> 8) >= 1 // >= v0.1.99 / 0x0100 + if (!mapnik::util::string2int(val,config.alpha_quality)) + { + throw ImageWriterException("invalid webp alpha_quality: '" + val + "'"); + } + #else + #ifdef _MSC_VER + #pragma NOTE(compiling against webp that does not support the alpha_quality flag) + #else + #warning "compiling against webp that does not support the alpha_quality flag" + #endif + throw ImageWriterException("your webp version does not support the alpha_quality option"); + #endif + } + } + else if (boost::algorithm::starts_with(t, "pass=")) + { + std::string val = t.substr(5); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.pass)) + { + throw ImageWriterException("invalid webp pass: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "preprocessing=")) + { + std::string val = t.substr(14); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.preprocessing)) + { + throw ImageWriterException("invalid webp preprocessing: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "partitions=")) + { + std::string val = t.substr(11); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.partitions)) + { + throw ImageWriterException("invalid webp partitions: '" + val + "'"); + } + } + } + else if (boost::algorithm::starts_with(t, "partition_limit=")) + { + std::string val = t.substr(16); + if (!val.empty()) + { + if (!mapnik::util::string2int(val,config.partition_limit)) + { + throw ImageWriterException("invalid webp partition_limit: '" + val + "'"); + } + } + } + else + { + throw ImageWriterException("unhandled webp option: " + t); + } + } + } +} +#endif + +webp_saver::webp_saver(std::ostream & stream, std::string const& t): + stream_(stream), t_(t) {} + +template<> +void webp_saver::operator() (image_null const& image) const +{ + throw ImageWriterException("null images not supported"); +} + +template +void process_rgba8_webp(T const& image, std::string const& t, std::ostream & stream) +{ +#if defined(HAVE_WEBP) + WebPConfig config; + // Default values set here will be lossless=0 and quality=75 (as least as of webp v0.3.1) + if (!WebPConfigInit(&config)) + { + throw std::runtime_error("version mismatch"); + } + // see for more details: https://github.com/mapnik/mapnik/wiki/Image-IO#webp-output-options + bool alpha = true; + handle_webp_options(t,config,alpha); + save_as_webp(stream,image,config,alpha); +#else + throw ImageWriterException("webp output is not enabled in your build of Mapnik"); +#endif +} + +template <> +void webp_saver::operator() (image_rgba8 const& image) const +{ + process_rgba8_webp(image, t_, stream_); +} + +template <> +void webp_saver::operator() (image_view_rgba8 const& image) const +{ + process_rgba8_webp(image, t_, stream_); +} + +template +void webp_saver::operator() (T const& image) const +{ + throw ImageWriterException("Mapnik does not support webp grayscale images"); +} + +template void webp_saver::operator() (image_rgba8 const& image) const; +template void webp_saver::operator() (image_gray8 const& image) const; +template void webp_saver::operator() (image_gray8s const& image) const; +template void webp_saver::operator() (image_gray16 const& image) const; +template void webp_saver::operator() (image_gray16s const& image) const; +template void webp_saver::operator() (image_gray32 const& image) const; +template void webp_saver::operator() (image_gray32s const& image) const; +template void webp_saver::operator() (image_gray32f const& image) const; +template void webp_saver::operator() (image_gray64 const& image) const; +template void webp_saver::operator() (image_gray64s const& image) const; +template void webp_saver::operator() (image_gray64f const& image) const; +template void webp_saver::operator() (image_view_rgba8 const& image) const; +template void webp_saver::operator() (image_view_gray8 const& image) const; +template void webp_saver::operator() (image_view_gray8s const& image) const; +template void webp_saver::operator() (image_view_gray16 const& image) const; +template void webp_saver::operator() (image_view_gray16s const& image) const; +template void webp_saver::operator() (image_view_gray32 const& image) const; +template void webp_saver::operator() (image_view_gray32s const& image) const; +template void webp_saver::operator() (image_view_gray32f const& image) const; +template void webp_saver::operator() (image_view_gray64 const& image) const; +template void webp_saver::operator() (image_view_gray64s const& image) const; +template void webp_saver::operator() (image_view_gray64f const& image) const; + +} // end ns diff --git a/src/jpeg_reader.cpp b/src/jpeg_reader.cpp index 48ac83e19..e375e9a10 100644 --- a/src/jpeg_reader.cpp +++ b/src/jpeg_reader.cpp @@ -85,9 +85,8 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return false; } - inline bool premultiplied_alpha() const final { return true; } - void read(unsigned x,unsigned y,image_data_rgba8& image) final; - image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; + void read(unsigned x,unsigned y,image_rgba8& image) final; + image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); static void on_error(j_common_ptr cinfo); @@ -266,7 +265,7 @@ boost::optional > jpeg_reader::bounding_box() const } template -void jpeg_reader::read(unsigned x0, unsigned y0, image_data_rgba8& image) +void jpeg_reader::read(unsigned x0, unsigned y0, image_rgba8& image) { stream_.clear(); stream_.seekg(0, std::ios_base::beg); @@ -321,11 +320,11 @@ void jpeg_reader::read(unsigned x0, unsigned y0, image_data_rgba8& image) } template -image_data_any jpeg_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) +image_any jpeg_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { - image_data_rgba8 data(width,height); + image_rgba8 data(width,height, true, true); read(x, y, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index c7d1b005f..e4daeb559 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -62,10 +62,7 @@ marker_cache::marker_cache() "" "" ""); - boost::optional bitmap_data = boost::optional(std::make_shared(4,4)); - (*bitmap_data)->set(0xff000000); - marker_ptr mark = std::make_shared(bitmap_data); - marker_cache_.emplace("image://square",mark); + marker_cache_.emplace("image://square",mapnik::marker_rgba8()); } marker_cache::~marker_cache() {} @@ -75,7 +72,7 @@ void marker_cache::clear() #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); #endif - using iterator_type = boost::unordered_map::const_iterator; + using iterator_type = boost::unordered_map::const_iterator; iterator_type itr = marker_cache_.begin(); while(itr != marker_cache_.end()) { @@ -112,33 +109,55 @@ bool marker_cache::insert_svg(std::string const& name, std::string const& svg_st return false; } -bool marker_cache::insert_marker(std::string const& uri, marker_ptr path) +bool marker_cache::insert_marker(std::string const& uri, mapnik::marker && path) { #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); #endif - return marker_cache_.emplace(uri,path).second; + return marker_cache_.emplace(uri,std::move(path)).second; } -boost::optional marker_cache::find(std::string const& uri, - bool update_cache) +namespace detail { - boost::optional result; +struct visitor_create_marker +{ + marker operator() (image_rgba8 & data) + { + mapnik::premultiply_alpha(data); + return mapnik::marker(mapnik::marker_rgba8(data)); + } + + marker operator() (image_null & data) + { + throw std::runtime_error("Can not make marker from null image data type"); + } + + template + marker operator() (T & data) + { + throw std::runtime_error("Can not make marker from this data type"); + } +}; + +} // end detail ns + +marker const& marker_cache::find(std::string const& uri, + bool update_cache) +{ if (uri.empty()) { - return result; + return std::move(mapnik::marker(mapnik::marker_null())); } #ifdef MAPNIK_THREADSAFE mapnik::scoped_lock lock(mutex_); #endif - using iterator_type = boost::unordered_map::const_iterator; + using iterator_type = boost::unordered_map::const_iterator; iterator_type itr = marker_cache_.find(uri); if (itr != marker_cache_.end()) { - result.reset(itr->second); - return result; + return itr->second; } try @@ -150,7 +169,7 @@ boost::optional marker_cache::find(std::string const& uri, if (mark_itr == svg_cache_.end()) { MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; - return result; + return std::move(mapnik::marker(mapnik::marker_null())); } std::string known_svg_string = mark_itr->second; using namespace mapnik::svg; @@ -165,11 +184,14 @@ boost::optional marker_cache::find(std::string const& uri, svg.bounding_rect(&lox, &loy, &hix, &hiy); marker_path->set_bounding_box(lox,loy,hix,hiy); marker_path->set_dimensions(svg.width(),svg.height()); - marker_ptr mark(std::make_shared(marker_path)); - result.reset(mark); if (update_cache) { - marker_cache_.emplace(uri,*result); + auto emplace_result = marker_cache_.emplace(uri,mapnik::marker(std::move(mapnik::marker_svg(marker_path)))); + return emplace_result.first->second; + } + else + { + return std::move(mapnik::marker(std::move(mapnik::marker_svg(marker_path)))); } } // otherwise assume file-based @@ -178,7 +200,7 @@ boost::optional marker_cache::find(std::string const& uri, if (!mapnik::util::exists(uri)) { MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; - return result; + return std::move(mapnik::marker(mapnik::marker_null())); } if (is_svg(uri)) { @@ -194,11 +216,14 @@ boost::optional marker_cache::find(std::string const& uri, svg.bounding_rect(&lox, &loy, &hix, &hiy); marker_path->set_bounding_box(lox,loy,hix,hiy); marker_path->set_dimensions(svg.width(),svg.height()); - marker_ptr mark(std::make_shared(marker_path)); - result.reset(mark); if (update_cache) { - marker_cache_.emplace(uri,*result); + auto emplace_result = marker_cache_.emplace(uri,mapnik::marker(std::move(mapnik::marker_svg(marker_path)))); + return emplace_result.first->second; + } + else + { + return std::move(mapnik::marker(std::move(mapnik::marker_svg(marker_path)))); } } else @@ -210,24 +235,21 @@ boost::optional marker_cache::find(std::string const& uri, unsigned width = reader->width(); unsigned height = reader->height(); BOOST_ASSERT(width > 0 && height > 0); - mapnik::image_ptr image(std::make_shared(width,height)); - reader->read(0,0,*image); - if (!reader->premultiplied_alpha()) - { - agg::rendering_buffer buffer(image->getBytes(),image->width(),image->height(),image->width() * 4); - agg::pixfmt_rgba32 pixf(buffer); - pixf.premultiply(); - } - marker_ptr mark(std::make_shared(image)); - result.reset(mark); + image_any im = reader->read(0,0,width,height); if (update_cache) { - marker_cache_.emplace(uri,*result); + auto emplace_result = marker_cache_.emplace(uri,util::apply_visitor(detail::visitor_create_marker(), im)); + return emplace_result.first->second; + } + else + { + return std::move(util::apply_visitor(detail::visitor_create_marker(), im)); } } else { MAPNIK_LOG_ERROR(marker_cache) << "could not intialize reader for: '" << uri << "'"; + return std::move(mapnik::marker(mapnik::marker_null())); } } } @@ -236,7 +258,7 @@ boost::optional marker_cache::find(std::string const& uri, { MAPNIK_LOG_ERROR(marker_cache) << "Exception caught while loading: '" << uri << "' (" << ex.what() << ")"; } - return result; + return std::move(mapnik::marker(mapnik::marker_null())); } } diff --git a/src/miniz_png.cpp b/src/miniz_png.cpp index d968d1dae..3a32d50f3 100644 --- a/src/miniz_png.cpp +++ b/src/miniz_png.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include // miniz @@ -361,11 +361,11 @@ const mz_uint8 PNGWriter::IEND_tpl[] = { 'I', 'E', 'N', 'D' // "IEND" }; -template void PNGWriter::writeIDAT(image_data_gray8 const& image); -template void PNGWriter::writeIDAT >(image_view const& image); -template void PNGWriter::writeIDAT(image_data_rgba8 const& image); -template void PNGWriter::writeIDAT >(image_view const& image); -template void PNGWriter::writeIDATStripAlpha(image_data_rgba8 const& image); -template void PNGWriter::writeIDATStripAlpha >(image_view const& image); +template void PNGWriter::writeIDAT(image_gray8 const& image); +template void PNGWriter::writeIDAT(image_view_gray8 const& image); +template void PNGWriter::writeIDAT(image_rgba8 const& image); +template void PNGWriter::writeIDAT(image_view_rgba8 const& image); +template void PNGWriter::writeIDATStripAlpha(image_rgba8 const& image); +template void PNGWriter::writeIDATStripAlpha(image_view_rgba8 const& image); }} diff --git a/src/png_reader.cpp b/src/png_reader.cpp index 318a67b47..0773a4164 100644 --- a/src/png_reader.cpp +++ b/src/png_reader.cpp @@ -80,9 +80,8 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - bool premultiplied_alpha() const final { return false; } //http://www.libpng.org/pub/png/spec/1.1/PNG-Rationale.html - void read(unsigned x,unsigned y,image_data_rgba8& image) final; - image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; + void read(unsigned x,unsigned y,image_rgba8& image) final; + image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length); @@ -227,7 +226,7 @@ boost::optional > png_reader::bounding_box() const } template -void png_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) +void png_reader::read(unsigned x0, unsigned y0,image_rgba8& image) { stream_.clear(); stream_.seekg(0, std::ios_base::beg); @@ -311,11 +310,11 @@ void png_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) template -image_data_any png_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) +image_any png_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { - image_data_rgba8 data(width,height); + image_rgba8 data(width,height); read(x, y, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } diff --git a/src/raster_colorizer.cpp b/src/raster_colorizer.cpp index 9bed5500a..bd150d540 100644 --- a/src/raster_colorizer.cpp +++ b/src/raster_colorizer.cpp @@ -123,12 +123,12 @@ bool raster_colorizer::add_stop(colorizer_stop const& stop) } template -void raster_colorizer::colorize(image_data_rgba8 & out, T const& in, +void raster_colorizer::colorize(image_rgba8 & out, T const& in, boost::optional const& nodata, feature_impl const& f) const { - using image_data_type = T; - using pixel_type = typename image_data_type::pixel_type; + using image_type = T; + using pixel_type = typename image_type::pixel_type; // TODO: assuming in/out have the same width/height for now std::uint32_t * out_data = out.getData(); pixel_type const* in_data = in.getData(); @@ -286,13 +286,34 @@ unsigned raster_colorizer::get_color(float value) const } -template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray8 const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_gray8 const& in, boost::optionalconst& nodata, feature_impl const& f) const; -template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray16 const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_gray8s const& in, boost::optionalconst& nodata, feature_impl const& f) const; -template void raster_colorizer::colorize(image_data_rgba8 & out, image_data_gray32f const& in, +template void raster_colorizer::colorize(image_rgba8 & out, image_gray16 const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray16s const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray32 const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray32s const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray32f const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray64 const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray64s const& in, + boost::optionalconst& nodata, + feature_impl const& f) const; +template void raster_colorizer::colorize(image_rgba8 & out, image_gray64f const& in, boost::optionalconst& nodata, feature_impl const& f) const; diff --git a/src/renderer_common/process_group_symbolizer.cpp b/src/renderer_common/process_group_symbolizer.cpp index 669de0d09..3725220fb 100644 --- a/src/renderer_common/process_group_symbolizer.cpp +++ b/src/renderer_common/process_group_symbolizer.cpp @@ -39,7 +39,7 @@ vector_marker_render_thunk::vector_marker_render_thunk(svg_path_ptr const& src, comp_op_(comp_op), snap_to_pixels_(snap_to_pixels) {} -raster_marker_render_thunk::raster_marker_render_thunk(image_data_rgba8 & src, +raster_marker_render_thunk::raster_marker_render_thunk(image_rgba8 const& src, agg::trans_affine const& marker_trans, double opacity, composite_mode_e comp_op, @@ -97,7 +97,7 @@ private: template struct raster_marker_thunk_dispatch : public raster_markers_dispatch { - raster_marker_thunk_dispatch(image_data_rgba8 & src, + raster_marker_thunk_dispatch(image_rgba8 const& src, agg::trans_affine const& marker_trans, symbolizer_base const& sym, Detector & detector, @@ -125,7 +125,7 @@ private: render_thunk_list & thunks_; }; -} +} // end detail ns render_thunk_extractor::render_thunk_extractor(box2d & box, render_thunk_list & thunks, diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp index bb404cdb0..fc9a047a0 100644 --- a/src/renderer_common/render_pattern.cpp +++ b/src/renderer_common/render_pattern.cpp @@ -30,42 +30,44 @@ #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" +#include "agg_pixfmt_gray.h" #include "agg_color_rgba.h" +#include "agg_color_gray.h" #include "agg_scanline_u.h" namespace mapnik { -std::shared_ptr render_pattern(rasterizer & ras, - marker const& marker, - agg::trans_affine const& tr, - double opacity) +template <> +void render_pattern(rasterizer & ras, + marker_svg const& marker, + agg::trans_affine const& tr, + double opacity, + image_rgba8 & image) { using pixfmt = agg::pixfmt_rgba32_pre; using renderer_base = agg::renderer_base; using renderer_solid = agg::renderer_scanline_aa_solid; agg::scanline_u8 sl; - mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box() * tr; + mapnik::box2d const& bbox = marker.bounding_box() * tr; mapnik::coord c = bbox.center(); agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); mtx.translate(0.5 * bbox.width(), 0.5 * bbox.height()); mtx = tr * mtx; - std::shared_ptr image = std::make_shared(bbox.width(), bbox.height()); - agg::rendering_buffer buf(image->getBytes(), image->width(), image->height(), image->width() * 4); + agg::rendering_buffer buf(image.getBytes(), image.width(), image.height(), image.getRowSize()); pixfmt pixf(buf); renderer_base renb(pixf); - mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); + mapnik::svg::vertex_stl_adapter stl_storage(marker.get_data()->source()); mapnik::svg::svg_path_adapter svg_path(stl_storage); mapnik::svg::svg_renderer_agg, renderer_solid, - agg::pixfmt_rgba32_pre > svg_renderer(svg_path, - (*marker.get_vector_data())->attributes()); + pixfmt > svg_renderer(svg_path, + marker.get_data()->attributes()); svg_renderer.render(ras, sl, renb, mtx, opacity, bbox); - return image; } } // namespace mapnik diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index b57c2d8ef..25566e9c4 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -22,11 +22,12 @@ // mapnik #include -#include #include #include #include #include +#include +#include namespace mapnik { @@ -102,7 +103,7 @@ void composite_bitmap(T & pixmap, FT_Bitmap *bitmap, unsigned rgba, int x, int y unsigned gray=bitmap->buffer[q*bitmap->width+p]; if (gray) { - pixmap.composite_pixel(comp_op, i, j, rgba, gray, opacity); + mapnik::composite_pixel(pixmap, comp_op, i, j, rgba, gray, opacity); } } } @@ -291,17 +292,17 @@ void agg_text_renderer::render_halo(FT_Bitmap *bitmap, int gray = bitmap->buffer[y*bitmap->width+x]; if (gray) { - pixmap_.composite_pixel(comp_op, x+x1-1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1, y+y1-1, rgba, gray*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1+1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1-1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1, y+y1-1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1+1, y+y1-1, rgba, gray*halo_radius*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1-1, y+y1, rgba, gray*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1, y+y1, rgba, gray, opacity); - pixmap_.composite_pixel(comp_op, x+x1+1, y+y1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1-1, y+y1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1, y+y1, rgba, gray, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1+1, y+y1, rgba, gray*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1-1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1, y+y1+1, rgba, gray*halo_radius, opacity); - pixmap_.composite_pixel(comp_op, x+x1+1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1-1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1, y+y1+1, rgba, gray*halo_radius, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1+1, y+y1+1, rgba, gray*halo_radius*halo_radius, opacity); } } } @@ -317,7 +318,7 @@ void agg_text_renderer::render_halo(FT_Bitmap *bitmap, { for (int n=-halo_radius; n <=halo_radius; ++n) for (int m=-halo_radius; m <= halo_radius; ++m) - pixmap_.composite_pixel(comp_op, x+x1+m, y+y1+n, rgba, gray, opacity); + mapnik::composite_pixel(pixmap_, comp_op, x+x1+m, y+y1+n, rgba, gray, opacity); } } } @@ -357,7 +358,7 @@ grid_text_renderer::grid_text_renderer(pixmap_type &pixmap, : text_renderer(HALO_RASTERIZER_FAST, comp_op, src_over, scale_factor), pixmap_(pixmap) {} -template class agg_text_renderer; +template class agg_text_renderer; template class grid_text_renderer; } // namespace mapnik diff --git a/src/text/symbolizer_helpers.cpp b/src/text/symbolizer_helpers.cpp index 8002cf305..70106de32 100644 --- a/src/text/symbolizer_helpers.cpp +++ b/src/text/symbolizer_helpers.cpp @@ -302,13 +302,13 @@ void text_symbolizer_helper::init_marker() const { std::string filename = mapnik::get(sym_, feature_, vars_); if (filename.empty()) return; - boost::optional marker = marker_cache::instance().find(filename, true); - if (!marker) return; + mapnik::marker const& marker = marker_cache::instance().find(filename, true); + if (marker.is()) return; agg::trans_affine trans; auto image_transform = get_optional(sym_, keys::image_transform); if (image_transform) evaluate_transform(trans, feature_, vars_, *image_transform); - double width = (*marker)->width(); - double height = (*marker)->height(); + double width = marker.width(); + double height = marker.height(); double px0 = - 0.5 * width; double py0 = - 0.5 * height; double px1 = 0.5 * width; @@ -329,7 +329,7 @@ void text_symbolizer_helper::init_marker() const value_double shield_dy = mapnik::get(sym_, feature_, vars_); pixel_position marker_displacement; marker_displacement.set(shield_dx,shield_dy); - finder_.set_marker(std::make_shared(*marker, trans), bbox, unlock_image, marker_displacement); + finder_.set_marker(std::make_shared(marker, trans), bbox, unlock_image, marker_displacement); } diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 002b25cd4..b9fe5a074 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -132,11 +132,11 @@ private: std::size_t height_; boost::optional > bbox_; unsigned bps_; + unsigned sample_format_; unsigned photometric_; unsigned bands_; unsigned planar_config_; unsigned compression_; - bool premultiplied_alpha_; bool has_alpha_; bool is_tiled_; @@ -153,11 +153,11 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - bool premultiplied_alpha() const final; - void read(unsigned x,unsigned y,image_data_rgba8& image) final; - image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; + void read(unsigned x,unsigned y,image_rgba8& image) final; + image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; // methods specific to tiff reader unsigned bits_per_sample() const { return bps_; } + unsigned sample_format() const { return sample_format_; } unsigned photometric() const { return photometric_; } bool is_tiled() const { return is_tiled_; } unsigned tile_width() const { return tile_width_; } @@ -169,14 +169,14 @@ private: tiff_reader(const tiff_reader&); tiff_reader& operator=(const tiff_reader&); void init(); - void read_generic(unsigned x,unsigned y,image_data_rgba8& image); - void read_stripped(unsigned x,unsigned y,image_data_rgba8& image); + void read_generic(unsigned x,unsigned y,image_rgba8& image); + void read_stripped(unsigned x,unsigned y,image_rgba8& image); template void read_tiled(unsigned x,unsigned y, ImageData & image); template - image_data_any read_any_gray(unsigned x, unsigned y, unsigned width, unsigned height); + image_any read_any_gray(unsigned x, unsigned y, unsigned width, unsigned height); TIFF* open(std::istream & input); }; @@ -211,11 +211,11 @@ tiff_reader::tiff_reader(std::string const& file_name) width_(0), height_(0), bps_(0), + sample_format_(SAMPLEFORMAT_UINT), photometric_(0), bands_(1), planar_config_(PLANARCONFIG_CONTIG), compression_(COMPRESSION_NONE), - premultiplied_alpha_(false), has_alpha_(false), is_tiled_(false) { @@ -235,11 +235,11 @@ tiff_reader::tiff_reader(char const* data, std::size_t size) width_(0), height_(0), bps_(0), + sample_format_(SAMPLEFORMAT_UINT), photometric_(0), bands_(1), planar_config_(PLANARCONFIG_CONTIG), compression_(COMPRESSION_NONE), - premultiplied_alpha_(false), has_alpha_(false), is_tiled_(false) { @@ -261,10 +261,12 @@ void tiff_reader::init() if (!tif) throw image_reader_exception("Can't open tiff file"); TIFFGetField(tif,TIFFTAG_BITSPERSAMPLE,&bps_); + TIFFGetField(tif,TIFFTAG_SAMPLEFORMAT,&sample_format_); TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photometric_); TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &bands_); MAPNIK_LOG_DEBUG(tiff_reader) << "bits per sample: " << bps_; + MAPNIK_LOG_DEBUG(tiff_reader) << "sample format: " << sample_format_; MAPNIK_LOG_DEBUG(tiff_reader) << "photometric: " << photometric_; MAPNIK_LOG_DEBUG(tiff_reader) << "bands: " << bands_; @@ -303,10 +305,10 @@ void tiff_reader::init() &extrasamples, &sampleinfo)) { has_alpha_ = true; - if (extrasamples == 1 && - sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA) + if (extrasamples > 0 && + sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED) { - premultiplied_alpha_ = true; + throw std::runtime_error("Unspecified provided for extra samples to tiff reader."); } } // Try extracting bounding box from geoTIFF tags @@ -373,13 +375,7 @@ boost::optional > tiff_reader::bounding_box() const } template -bool tiff_reader::premultiplied_alpha() const -{ - return premultiplied_alpha_; -} - -template -void tiff_reader::read(unsigned x,unsigned y,image_data_rgba8& image) +void tiff_reader::read(unsigned x,unsigned y,image_rgba8& image) { if (read_method_==stripped) { @@ -397,22 +393,22 @@ void tiff_reader::read(unsigned x,unsigned y,image_data_rgba8& image) template template -image_data_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned width, unsigned height) +image_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned width, unsigned height) { - using image_data_type = ImageData; - using pixel_type = typename image_data_type::pixel_type; + using image_type = ImageData; + using pixel_type = typename image_type::pixel_type; if (read_method_ == tiled) { - image_data_type data(width,height); - read_tiled(x0, y0, data); - return image_data_any(std::move(data)); + image_type data(width,height); + read_tiled(x0, y0, data); + return image_any(std::move(data)); } else { TIFF* tif = open(stream_); if (tif) { - image_data_type data(width, height); + image_type data(width, height); std::size_t block_size = rows_per_strip_ > 0 ? rows_per_strip_ : tile_height_ ; std::ptrdiff_t start_y = y0 - y0 % block_size; std::ptrdiff_t end_y = std::min(y0 + height, static_cast(height_)); @@ -429,10 +425,10 @@ image_data_any tiff_reader::read_any_gray(unsigned x0, unsigned y0, unsigned std::transform(scanline.get() + start_x, scanline.get() + end_x, row, [](pixel_type const& p) { return p;}); } } - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } - return image_data_any(); + return image_any(); } @@ -456,8 +452,8 @@ struct rgb8_to_rgba8 template struct tiff_reader_traits { - using image_data_type = T; - using pixel_type = typename image_data_type::pixel_type; + using image_type = T; + using pixel_type = typename image_type::pixel_type; static bool read_tile(TIFF * tif, unsigned x, unsigned y, pixel_type* buf, std::size_t tile_width, std::size_t tile_height) { return (TIFFReadEncodedTile(tif, TIFFComputeTile(tif, x,y,0,0), buf, tile_width * tile_height * sizeof(pixel_type)) != -1); @@ -466,7 +462,7 @@ struct tiff_reader_traits // default specialization that expands into RGBA template <> -struct tiff_reader_traits +struct tiff_reader_traits { using pixel_type = std::uint32_t; static bool read_tile(TIFF * tif, unsigned x0, unsigned y0, pixel_type* buf, std::size_t tile_width, std::size_t tile_height) @@ -486,7 +482,7 @@ struct tiff_reader_traits } template -image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigned height) +image_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, unsigned height) { if (width > 10000 || height > 10000) { @@ -501,67 +497,86 @@ image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, un { case 8: { - return read_any_gray(x0, y0, width, height); - } - case 16: - { - return read_any_gray(x0, y0, width, height); - } - case 32: - { - return read_any_gray(x0, y0, width, height); - } - } - } -// read PHOTOMETRIC_RGB expand using RGBA interface -/* - case PHOTOMETRIC_RGB: - { - switch (bps_) - { - case 8: - { - TIFF* tif = open(stream_); - if (tif) + switch (sample_format_) { - image_data_rgba8 data(width, height); - std::size_t element_size = sizeof(detail::rgb8); - std::size_t size_to_allocate = (TIFFScanlineSize(tif) + element_size - 1)/element_size; - const std::unique_ptr scanline(new detail::rgb8[size_to_allocate]); - std::ptrdiff_t start_y = y0 - y0 % rows_per_strip_; - std::ptrdiff_t end_y = std::min(y0 + height, static_cast(height_)); - std::ptrdiff_t start_x = x0; - std::ptrdiff_t end_x = std::min(x0 + width, static_cast(width_)); - for (std::size_t y = start_y; y < end_y; ++y) - { - if (-1 != TIFFReadScanline(tif, scanline.get(), y)) - { - if (y >= y0) - { - image_data_rgba8::pixel_type * row = data.getRow(y - y0); - std::transform(scanline.get() + start_x, scanline.get() + end_x, row, detail::rgb8_to_rgba8()); - } - } - } - return image_data_any(std::move(data)); + case SAMPLEFORMAT_UINT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_INT: + { + return read_any_gray(x0, y0, width, height); + } + default: + { + throw std::runtime_error("tiff_reader: This sample format is not supported for this bits per sample"); + } } - return image_data_any(); } case 16: { - image_data_rgba8 data(width,height); - read(x0, y0, data); - return image_data_any(std::move(data)); + switch (sample_format_) + { + case SAMPLEFORMAT_UINT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_INT: + { + return read_any_gray(x0, y0, width, height); + } + default: + { + throw std::runtime_error("tiff_reader: This sample format is not supported for this bits per sample"); + } + } } case 32: { - image_data_rgba8 data(width,height); - read(x0, y0, data); - return image_data_any(std::move(data)); + switch (sample_format_) + { + case SAMPLEFORMAT_UINT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_INT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_IEEEFP: + { + return read_any_gray(x0, y0, width, height); + } + default: + { + throw std::runtime_error("tiff_reader: This sample format is not supported for this bits per sample"); + } + } + } + case 64: + { + switch (sample_format_) + { + case SAMPLEFORMAT_UINT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_INT: + { + return read_any_gray(x0, y0, width, height); + } + case SAMPLEFORMAT_IEEEFP: + { + return read_any_gray(x0, y0, width, height); + } + default: + { + throw std::runtime_error("tiff_reader: This sample format is not supported for this bits per sample"); + } + } } } } -*/ default: { //PHOTOMETRIC_PALETTE = 3; @@ -573,16 +588,16 @@ image_data_any tiff_reader::read(unsigned x0, unsigned y0, unsigned width, un //PHOTOMETRIC_ITULAB = 10; //PHOTOMETRIC_LOGL = 32844; //PHOTOMETRIC_LOGLUV = 32845; - image_data_rgba8 data(width,height); + image_rgba8 data(width,height, true, true); read(x0, y0, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } - return image_data_any(); + return image_any(); } template -void tiff_reader::read_generic(unsigned, unsigned, image_data_rgba8& image) +void tiff_reader::read_generic(unsigned, unsigned, image_rgba8& image) { TIFF* tif = open(stream_); if (tif) @@ -619,7 +634,7 @@ void tiff_reader::read_tiled(unsigned x0,unsigned y0, ImageData & image) { if (!detail::tiff_reader_traits::read_tile(tif, x, y, buf.get(), tile_width_, tile_height_)) { - std::clog << "read_tile(...) failed at " << x << "/" << y << " for " << width_ << "/" << height_ << "\n"; + MAPNIK_LOG_DEBUG(tiff_reader) << "read_tile(...) failed at " << x << "/" << y << " for " << width_ << "/" << height_ << "\n"; break; } int tx0 = std::max(x0, static_cast(x)); @@ -636,40 +651,36 @@ void tiff_reader::read_tiled(unsigned x0,unsigned y0, ImageData & image) template -void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_data_rgba8& image) +void tiff_reader::read_stripped(unsigned x0,unsigned y0,image_rgba8& image) { TIFF* tif = open(stream_); if (tif) { - image_data_rgba8 strip(width_,rows_per_strip_,false); + image_rgba8 strip(width_,rows_per_strip_,false); int width=image.width(); int height=image.height(); unsigned start_y=(y0/rows_per_strip_)*rows_per_strip_; - unsigned end_y=((y0+height)/rows_per_strip_+1)*rows_per_strip_; - bool laststrip=(static_cast(end_y) > height_)?true:false; - int row,tx0,tx1,ty0,ty1; + unsigned end_y=std::min(y0+height, static_cast(height_)); + int tx0,tx1,ty0,ty1; tx0=x0; tx1=std::min(width+x0,static_cast(width_)); - + int row = 0; for (unsigned y=start_y; y < end_y; y+=rows_per_strip_) { ty0 = std::max(y0,y)-y; - ty1 = std::min(height+y0,y+rows_per_strip_)-y; + ty1 = std::min(end_y,y+rows_per_strip_)-y; if (!TIFFReadRGBAStrip(tif,y,strip.getData())) { - std::clog << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n"; + MAPNIK_LOG_DEBUG(tiff_reader) << "TIFFReadRGBAStrip failed at " << y << " for " << width_ << "/" << height_ << "\n"; break; } - row=y+ty0-y0; - - int n0=laststrip ? 0:(rows_per_strip_-ty1); - int n1=laststrip ? (ty1-ty0-1):(rows_per_strip_-ty0-1); - for (int n=n1;n>=n0;--n) + // This is in reverse becauase the TIFFReadRGBAStrip reads inverted + for (unsigned ty = ty1; ty > ty0; --ty) { - image.setRow(row,tx0-x0,tx1-x0,&strip.getData()[n*width_+tx0]); + image.setRow(row,tx0-x0,tx1-x0,&strip.getData()[(ty-1)*width_+tx0]); ++row; } } diff --git a/src/warp.cpp b/src/warp.cpp index 16a81492d..be216bfa6 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -23,7 +23,7 @@ // mapnik #include #include -#include +#include #include #include #include @@ -53,12 +53,12 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& box2d const& target_ext, box2d const& source_ext, double offset_x, double offset_y, unsigned mesh_size, scaling_method_e scaling_method, double filter_factor) { - using image_data_type = T; - using pixel_type = typename image_data_type::pixel_type; - using pixfmt_pre = typename detail::agg_scaling_traits::pixfmt_pre; - using color_type = typename detail::agg_scaling_traits::color_type; + using image_type = T; + using pixel_type = typename image_type::pixel_type; + using pixfmt_pre = typename detail::agg_scaling_traits::pixfmt_pre; + using color_type = typename detail::agg_scaling_traits::color_type; using renderer_base = agg::renderer_base; - using interpolator_type = typename detail::agg_scaling_traits::interpolator_type; + using interpolator_type = typename detail::agg_scaling_traits::interpolator_type; constexpr std::size_t pixel_size = sizeof(pixel_type); @@ -70,8 +70,8 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& std::size_t mesh_nx = std::ceil(source.width()/double(mesh_size) + 1); std::size_t mesh_ny = std::ceil(source.height()/double(mesh_size) + 1); - image_data xs(mesh_nx, mesh_ny); - image_data ys(mesh_nx, mesh_ny); + image_gray64f xs(mesh_nx, mesh_ny, false); + image_gray64f ys(mesh_nx, mesh_ny, false); // Precalculate reprojected mesh for(std::size_t j = 0; j < mesh_ny; ++j) @@ -138,13 +138,13 @@ MAPNIK_DECL void warp_image (T & target, T const& source, proj_transform const& interpolator_type interpolator(tr); if (scaling_method == SCALING_NEAR) { - using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; + using span_gen_type = typename detail::agg_scaling_traits::span_image_filter; span_gen_type sg(ia, interpolator); agg::render_scanlines_bin(rasterizer, scanline, rb, sa, sg); } else { - using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; + using span_gen_type = typename detail::agg_scaling_traits::span_image_resample_affine; agg::image_filter_lut filter; detail::set_scaling_method(filter, scaling_method, filter_factor); span_gen_type sg(ia, interpolator, filter); @@ -172,16 +172,16 @@ struct warp_image_visitor scaling_method_(scaling_method), filter_factor_(filter_factor) {} - void operator() (image_data_null const&) {} + void operator() (image_null const&) {} template void operator() (T const& source) { - using image_data_type = T; + using image_type = T; //source and target image data types must match - if (target_raster_.data_.template is()) + if (target_raster_.data_.template is()) { - image_data_type & target = util::get(target_raster_.data_); + image_type & target = util::get(target_raster_.data_); warp_image (target, source, prj_trans_, target_raster_.ext_, source_ext_, offset_x_, offset_y_, mesh_size_, scaling_method_, filter_factor_); } @@ -210,16 +210,16 @@ void reproject_and_scale_raster(raster & target, raster const& source, util::apply_visitor(warper, source.data_); } -template MAPNIK_DECL void warp_image (image_data_rgba8&, image_data_rgba8 const&, proj_transform const&, +template MAPNIK_DECL void warp_image (image_rgba8&, image_rgba8 const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); -template MAPNIK_DECL void warp_image (image_data_gray8&, image_data_gray8 const&, proj_transform const&, +template MAPNIK_DECL void warp_image (image_gray8&, image_gray8 const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); -template MAPNIK_DECL void warp_image (image_data_gray16&, image_data_gray16 const&, proj_transform const&, +template MAPNIK_DECL void warp_image (image_gray16&, image_gray16 const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); -template MAPNIK_DECL void warp_image (image_data_gray32f&, image_data_gray32f const&, proj_transform const&, +template MAPNIK_DECL void warp_image (image_gray32f&, image_gray32f const&, proj_transform const&, box2d const&, box2d const&, double, double, unsigned, scaling_method_e, double); diff --git a/src/webp_reader.cpp b/src/webp_reader.cpp index 6add17485..967fb0469 100644 --- a/src/webp_reader.cpp +++ b/src/webp_reader.cpp @@ -124,9 +124,8 @@ public: unsigned height() const final; boost::optional > bounding_box() const final; inline bool has_alpha() const final { return has_alpha_; } - bool premultiplied_alpha() const final { return false; } - void read(unsigned x,unsigned y,image_data_rgba8& image) final; - image_data_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; + void read(unsigned x,unsigned y,image_rgba8& image) final; + image_any read(unsigned x, unsigned y, unsigned width, unsigned height) final; private: void init(); }; @@ -237,7 +236,7 @@ boost::optional > webp_reader::bounding_box() const } template -void webp_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) +void webp_reader::read(unsigned x0, unsigned y0,image_rgba8& image) { WebPDecoderConfig config; config_guard guard(config); @@ -269,11 +268,11 @@ void webp_reader::read(unsigned x0, unsigned y0,image_data_rgba8& image) } template -image_data_any webp_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) +image_any webp_reader::read(unsigned x, unsigned y, unsigned width, unsigned height) { - image_data_rgba8 data(width,height); + image_rgba8 data(width,height); read(x, y, data); - return image_data_any(std::move(data)); + return image_any(std::move(data)); } } diff --git a/tests/cpp_tests/exceptions_test.cpp b/tests/cpp_tests/exceptions_test.cpp index 1bfc826e0..de3008f1b 100644 --- a/tests/cpp_tests/exceptions_test.cpp +++ b/tests/cpp_tests/exceptions_test.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -83,8 +82,8 @@ int main(int argc, char** argv) mapnik::Map m = map; m.add_layer(l); m.zoom_all(); - mapnik::image_32 im(m.width(),m.height()); - mapnik::agg_renderer ren(m,im); + mapnik::image_rgba8 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); //std::clog << mapnik::save_map_to_string(m) << "\n"; BOOST_TEST(true); // should throw here with "CSV Plugin: no attribute 'foo'. Valid attributes are: x,y." diff --git a/tests/cpp_tests/fontset_runtime_test.cpp b/tests/cpp_tests/fontset_runtime_test.cpp index 1b7cc59f9..a0045e646 100644 --- a/tests/cpp_tests/fontset_runtime_test.cpp +++ b/tests/cpp_tests/fontset_runtime_test.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -82,8 +81,8 @@ int main(int argc, char** argv) m.insert_style("style", std::move(the_style) ); m.zoom_to_box(mapnik::box2d(-256,-256, 256,256)); - mapnik::image_32 buf(m.width(),m.height()); - mapnik::agg_renderer ren(m,buf); + mapnik::image_rgba8 buf(m.width(),m.height()); + mapnik::agg_renderer ren(m,buf); ren.apply(); } catch (std::exception const& ex) { BOOST_TEST_EQ(std::string(ex.what()),std::string("Unable to find specified font face 'DejaVu Sans Book' in font set: 'fontset'")); diff --git a/tests/cpp_tests/image_io_test.cpp b/tests/cpp_tests/image_io_test.cpp index f7cb158f6..1ea4008cf 100644 --- a/tests/cpp_tests/image_io_test.cpp +++ b/tests/cpp_tests/image_io_test.cpp @@ -1,7 +1,6 @@ #include #include -#include -#include +#include #include #include #include @@ -46,17 +45,7 @@ int main(int argc, char** argv) try { - mapnik::image_32 im(-10,-10); // should throw rather than overflow - BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail - } - catch (std::exception const& ex) - { - BOOST_TEST( true ); // should hit bad alloc here - } - - try - { - mapnik::image_data_rgba8 im(-10,-10); // should throw rather than overflow + mapnik::image_rgba8 im(-10,-10); // should throw rather than overflow BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail } catch (std::exception const& ex) @@ -68,7 +57,7 @@ int main(int argc, char** argv) mapnik::cairo_surface_ptr image_surface( cairo_image_surface_create(CAIRO_FORMAT_ARGB32,256,257), mapnik::cairo_surface_closer()); - mapnik::image_data_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); + mapnik::image_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); im_data.set(1); BOOST_TEST( (unsigned)im_data(0,0) == unsigned(1) ); // Should set back to fully transparent diff --git a/tests/cpp_tests/image_painted_test.cpp b/tests/cpp_tests/image_painted_test.cpp index 946c21124..b58a87e07 100644 --- a/tests/cpp_tests/image_painted_test.cpp +++ b/tests/cpp_tests/image_painted_test.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -60,8 +59,8 @@ int main(int argc, char** argv) m.zoom_all(); - image_32 image(m.width(), m.height()); - agg_renderer ren(m, image); + image_rgba8 image(m.width(), m.height()); + agg_renderer ren(m, image); ren.apply(); BOOST_TEST_EQ(image.painted(), true); diff --git a/tests/cpp_tests/map_request_test.cpp b/tests/cpp_tests/map_request_test.cpp index b7f2deb64..45e9ec411 100644 --- a/tests/cpp_tests/map_request_test.cpp +++ b/tests/cpp_tests/map_request_test.cpp @@ -7,11 +7,10 @@ #if defined(HAVE_CAIRO) #include #endif -#include #include #include #include -#include +#include #include #include #include @@ -30,19 +29,19 @@ bool compare_images(std::string const& src_fn,std::string const& dest_fn) { throw mapnik::image_reader_exception("Failed to load: " + dest_fn); } - std::shared_ptr image_ptr1 = std::make_shared(reader1->width(),reader1->height()); - reader1->read(0,0,image_ptr1->data()); + std::shared_ptr image_ptr1 = std::make_shared(reader1->width(),reader1->height()); + reader1->read(0,0,*image_ptr1); std::unique_ptr reader2(mapnik::get_image_reader(src_fn,"png")); if (!reader2.get()) { throw mapnik::image_reader_exception("Failed to load: " + src_fn); } - std::shared_ptr image_ptr2 = std::make_shared(reader2->width(),reader2->height()); - reader2->read(0,0,image_ptr2->data()); + std::shared_ptr image_ptr2 = std::make_shared(reader2->width(),reader2->height()); + reader2->read(0,0,*image_ptr2); - image_data_rgba8 const& dest = image_ptr1->data(); - image_data_rgba8 const& src = image_ptr2->data(); + image_rgba8 const& dest = *image_ptr1; + image_rgba8 const& src = *image_ptr2; unsigned int width = src.width(); unsigned int height = src.height(); @@ -78,21 +77,21 @@ int main(int argc, char** argv) mapnik::Map m(256,256); mapnik::load_map(m,"./tests/data/good_maps/marker-text-line.xml",false); m.zoom_all(); - mapnik::image_32 im(m.width(),m.height()); + mapnik::image_rgba8 im(m.width(),m.height()); double scale_factor = 1.2; // render normally with apply() and just map and image - mapnik::agg_renderer renderer1(m,im,scale_factor); + mapnik::agg_renderer renderer1(m,im,scale_factor); renderer1.apply(); std::string actual1("/tmp/map-request-marker-text-line-actual1.png"); - //mapnik::save_to_file(im.data(),expected); - mapnik::save_to_file(im.data(),actual1); + //mapnik::save_to_file(im,expected); + mapnik::save_to_file(im,actual1); // TODO - re-enable if we can control the freetype/cairo versions used // https://github.com/mapnik/mapnik/issues/1868 //BOOST_TEST(compare_images(actual1,expected)); // reset image - im.clear(); + mapnik::fill(im, 0); // set up a mapnik::request object mapnik::request req(m.width(),m.height(),m.get_current_extent()); @@ -100,19 +99,19 @@ int main(int argc, char** argv) // render using apply() and mapnik::request mapnik::attributes vars; - mapnik::agg_renderer renderer2(m,req,vars,im,scale_factor); + mapnik::agg_renderer renderer2(m,req,vars,im,scale_factor); renderer2.apply(); std::string actual2("/tmp/map-request-marker-text-line-actual2.png"); - mapnik::save_to_file(im.data(),actual2); + mapnik::save_to_file(im,actual2); // TODO - re-enable if we can control the freetype/cairo versions used // https://github.com/mapnik/mapnik/issues/1868 //BOOST_TEST(compare_images(actual2,expected)); // reset image - im.clear(); + mapnik::fill(im, 0); // render with apply_to_layer api and mapnik::request params passed to apply_to_layer - mapnik::agg_renderer renderer3(m,req,vars,im,scale_factor); + mapnik::agg_renderer renderer3(m,req,vars,im,scale_factor); renderer3.start_map_processing(m); mapnik::projection map_proj(m.srs(),true); double scale_denom = mapnik::scale_denominator(req.scale(),map_proj.is_geographic()); @@ -137,7 +136,7 @@ int main(int argc, char** argv) } renderer3.end_map_processing(m); std::string actual3("/tmp/map-request-marker-text-line-actual3.png"); - mapnik::save_to_file(im.data(),actual3); + mapnik::save_to_file(im,actual3); // TODO - re-enable if we can control the freetype/cairo versions used // https://github.com/mapnik/mapnik/issues/1868 //BOOST_TEST(compare_images(actual3,expected)); diff --git a/tests/cpp_tests/utils.hpp b/tests/cpp_tests/utils.hpp index e82281635..b4a541adc 100644 --- a/tests/cpp_tests/utils.hpp +++ b/tests/cpp_tests/utils.hpp @@ -23,4 +23,4 @@ inline static bool set_working_dir(std::vector args) return false; } return true; -} \ No newline at end of file +} diff --git a/tests/cxx/test_main.cpp b/tests/cxx/test_main.cpp index 063e87874..0c7c351f4 100644 --- a/tests/cxx/test_main.cpp +++ b/tests/cxx/test_main.cpp @@ -1,2 +1,2 @@ #define CATCH_CONFIG_MAIN -#include "catch.hpp" \ No newline at end of file +#include "catch.hpp" diff --git a/tests/cxx/tiff_io.cpp b/tests/cxx/tiff_io.cpp index 37cfdddd4..7f7d798d1 100644 --- a/tests/cxx/tiff_io.cpp +++ b/tests/cxx/tiff_io.cpp @@ -26,32 +26,33 @@ REQUIRE( reader2->width() == 256 ); \ REQUIRE( reader2->height() == 256 ); \ -#define TIFF_ASSERT_ALPHA \ +#define TIFF_ASSERT_ALPHA( data ) \ REQUIRE( tiff_reader.has_alpha() == true ); \ - REQUIRE( tiff_reader.premultiplied_alpha() == false ); \ REQUIRE( reader->has_alpha() == true ); \ - REQUIRE( reader->premultiplied_alpha() == false ); \ REQUIRE( tiff_reader2.has_alpha() == true ); \ - REQUIRE( tiff_reader2.premultiplied_alpha() == false ); \ REQUIRE( reader2->has_alpha() == true ); \ - REQUIRE( reader2->premultiplied_alpha() == false ); \ + REQUIRE( data.get_premultiplied() == true ); \ -#define TIFF_ASSERT_NO_ALPHA \ +#define TIFF_ASSERT_NO_ALPHA_RGB( data ) \ REQUIRE( tiff_reader.has_alpha() == false ); \ - REQUIRE( tiff_reader.premultiplied_alpha() == false ); \ REQUIRE( reader->has_alpha() == false ); \ - REQUIRE( reader->premultiplied_alpha() == false ); \ REQUIRE( tiff_reader2.has_alpha() == false ); \ - REQUIRE( tiff_reader2.premultiplied_alpha() == false ); \ REQUIRE( reader2->has_alpha() == false ); \ - REQUIRE( reader2->premultiplied_alpha() == false ); \ + REQUIRE( data.get_premultiplied() == true ); \ + +#define TIFF_ASSERT_NO_ALPHA_GRAY( data ) \ + REQUIRE( tiff_reader.has_alpha() == false ); \ + REQUIRE( reader->has_alpha() == false ); \ + REQUIRE( tiff_reader2.has_alpha() == false ); \ + REQUIRE( reader2->has_alpha() == false ); \ + REQUIRE( data.get_premultiplied() == false ); \ #define TIFF_ASSERT_SIZE( data,reader ) \ REQUIRE( data.width() == reader->width() ); \ REQUIRE( data.height() == reader->height() ); \ #define TIFF_READ_ONE_PIXEL \ - mapnik::image_data_any subimage = reader->read(1, 1, 1, 1); \ + mapnik::image_any subimage = reader->read(1, 1, 1, 1); \ REQUIRE( subimage.width() == 1 ); \ REQUIRE( subimage.height() == 1 ); \ @@ -80,10 +81,10 @@ SECTION("scan rgb8 striped") { std::unique_ptr reader2(mapnik::get_image_reader(file.data().get(),file.size())); REQUIRE( reader2->width() == 512 ); REQUIRE( reader2->height() == 512 ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_RGB( data ); TIFF_READ_ONE_PIXEL } @@ -110,10 +111,10 @@ SECTION("scan rgb8 tiled") { std::unique_ptr reader2(mapnik::get_image_reader(file.data().get(),file.size())); REQUIRE( reader2->width() == 512 ); REQUIRE( reader2->height() == 512 ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_RGB( data ); TIFF_READ_ONE_PIXEL } @@ -126,10 +127,10 @@ SECTION("rgba8 striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_ADOBE_DEFLATE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_ALPHA + TIFF_ASSERT_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -142,10 +143,10 @@ SECTION("rgba8 tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_ALPHA + TIFF_ASSERT_ALPHA( data ); TIFF_READ_ONE_PIXEL } @@ -158,10 +159,10 @@ SECTION("rgb8 striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_RGB( data ); TIFF_READ_ONE_PIXEL } @@ -174,10 +175,10 @@ SECTION("rgb8 tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_RGB ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_RGB( data ); TIFF_READ_ONE_PIXEL } @@ -190,10 +191,10 @@ SECTION("gray8 striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -206,10 +207,10 @@ SECTION("gray8 tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -222,10 +223,10 @@ SECTION("gray16 striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -238,10 +239,10 @@ SECTION("gray16 tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -254,10 +255,10 @@ SECTION("gray32f striped") { REQUIRE( tiff_reader.tile_height() == 0 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_NONE ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } @@ -270,10 +271,10 @@ SECTION("gray32f tiled") { REQUIRE( tiff_reader.tile_height() == 256 ); REQUIRE( tiff_reader.photometric() == PHOTOMETRIC_MINISBLACK ); REQUIRE( tiff_reader.compression() == COMPRESSION_LZW ); - mapnik::image_data_any data = reader->read(0, 0, reader->width(), reader->height()); - REQUIRE( data.is() == true ); + mapnik::image_any data = reader->read(0, 0, reader->width(), reader->height()); + REQUIRE( data.is() == true ); TIFF_ASSERT_SIZE( data,reader ); - TIFF_ASSERT_NO_ALPHA + TIFF_ASSERT_NO_ALPHA_GRAY( data ); TIFF_READ_ONE_PIXEL } diff --git a/tests/python_tests/buffer_clear_test.py b/tests/python_tests/buffer_clear_test.py index c89c1599a..0afd52d9c 100644 --- a/tests/python_tests/buffer_clear_test.py +++ b/tests/python_tests/buffer_clear_test.py @@ -13,7 +13,7 @@ def test_clearing_image_data(): bytes = im.tostring() eq_(im.tostring(),bytes) # set background, then clear - im.background = mapnik.Color('green') + im.fill(mapnik.Color('green')) eq_(im.tostring()!=bytes,True) # clear image, should now equal original im.clear() diff --git a/tests/python_tests/color_test.py b/tests/python_tests/color_test.py new file mode 100644 index 000000000..900faf11b --- /dev/null +++ b/tests/python_tests/color_test.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import os, mapnik +from timeit import Timer, time +from nose.tools import * +from utilities import execution_path, run_all, get_unique_colors + +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + +def test_color_init(): + c = mapnik.Color(12, 128, 255) + eq_(c.r, 12) + eq_(c.g, 128) + eq_(c.b, 255) + eq_(c.a, 255) + eq_(False, c.get_premultiplied()) + c = mapnik.Color(16, 32, 64, 128) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(False, c.get_premultiplied()) + c = mapnik.Color(16, 32, 64, 128,True) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(True, c.get_premultiplied()) + c = mapnik.Color('rgba(16,32,64,0.5)') + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(False, c.get_premultiplied()) + c = mapnik.Color('rgba(16,32,64,0.5)', True) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(True, c.get_premultiplied()) + hex_str = '#10204080' + c = mapnik.Color(hex_str) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(hex_str, c.to_hex_string()) + eq_(False, c.get_premultiplied()) + c = mapnik.Color(hex_str, True) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(hex_str, c.to_hex_string()) + eq_(True, c.get_premultiplied()) + rgba_int = 2151686160 + c = mapnik.Color(rgba_int) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(rgba_int, c.packed()) + eq_(False, c.get_premultiplied()) + c = mapnik.Color(rgba_int, True) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + eq_(rgba_int, c.packed()) + eq_(True, c.get_premultiplied()) + +def test_color_properties(): + c = mapnik.Color(16, 32, 64, 128) + eq_(c.r, 16) + eq_(c.g, 32) + eq_(c.b, 64) + eq_(c.a, 128) + c.r = 17 + eq_(c.r, 17) + c.g = 33 + eq_(c.g, 33) + c.b = 65 + eq_(c.b, 65) + c.a = 128 + eq_(c.a, 128) + +def test_color_premultiply(): + c = mapnik.Color(16, 33, 255, 128) + eq_(c.premultiply(), True) + eq_(c.r, 8) + eq_(c.g, 17) + eq_(c.b, 128) + eq_(c.a, 128) + # Repeating it again should do nothing + eq_(c.premultiply(), False) + eq_(c.r, 8) + eq_(c.g, 17) + eq_(c.b, 128) + eq_(c.a, 128) + c.demultiply() + c.demultiply() + # This will not return the same values as before but we expect that + eq_(c.r,15) + eq_(c.g,33) + eq_(c.b,255) + eq_(c.a,128) + +if __name__ == "__main__": + setup() + exit(run_all(eval(x) for x in dir() if x.startswith("test_"))) diff --git a/tests/python_tests/compare_test.py b/tests/python_tests/compare_test.py new file mode 100644 index 000000000..f4b656309 --- /dev/null +++ b/tests/python_tests/compare_test.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os, mapnik +from nose.tools import * +from utilities import execution_path, run_all + +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + +def test_another_compare(): + im = mapnik.Image(5,5) + im2 = mapnik.Image(5,5) + im2.fill(mapnik.Color('rgba(255,255,255,0)')) + eq_(im.compare(im2,16), im.width() * im.height()) + +def test_compare_rgba8(): + im = mapnik.Image(5,5,mapnik.ImageType.rgba8) + im.fill(mapnik.Color(0,0,0,0)) + eq_(im.compare(im), 0) + im2 = mapnik.Image(5,5,mapnik.ImageType.rgba8) + im2.fill(mapnik.Color(0,0,0,0)) + eq_(im.compare(im2), 0) + eq_(im2.compare(im), 0) + im2.fill(mapnik.Color(0,0,0,12)) + eq_(im.compare(im2), 25) + eq_(im.compare(im2, 0, False), 0) + im3 = mapnik.Image(5,5,mapnik.ImageType.rgba8) + im3.set_pixel(0,0, mapnik.Color(0,0,0,0)) + im3.set_pixel(0,1, mapnik.Color(1,1,1,1)) + im3.set_pixel(1,0, mapnik.Color(2,2,2,2)) + im3.set_pixel(1,1, mapnik.Color(3,3,3,3)) + eq_(im.compare(im3), 3) + eq_(im.compare(im3,1),2) + eq_(im.compare(im3,2),1) + eq_(im.compare(im3,3),0) + +def test_compare_2_image(): + im = mapnik.Image(5,5) + im.set_pixel(0,0, mapnik.Color(254, 254, 254, 254)) + im.set_pixel(4,4, mapnik.Color('white')) + im2 = mapnik.Image(5,5) + eq_(im2.compare(im,16), 2) + +def test_compare_dimensions(): + im = mapnik.Image(2,2) + im2 = mapnik.Image(3,3) + eq_(im.compare(im2), 4) + eq_(im2.compare(im), 9) + +def test_compare_gray8(): + im = mapnik.Image(2,2,mapnik.ImageType.gray8) + im.fill(0) + eq_(im.compare(im), 0) + im2 = mapnik.Image(2,2,mapnik.ImageType.gray8) + im2.fill(0) + eq_(im.compare(im2), 0) + eq_(im2.compare(im), 0) + eq_(im.compare(im2, 0, False), 0) + im3 = mapnik.Image(2,2,mapnik.ImageType.gray8) + im3.set_pixel(0,0,0) + im3.set_pixel(0,1,1) + im3.set_pixel(1,0,2) + im3.set_pixel(1,1,3) + eq_(im.compare(im3),3) + eq_(im.compare(im3,1),2) + eq_(im.compare(im3,2),1) + eq_(im.compare(im3,3),0) + +def test_compare_gray16(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + im.fill(0) + eq_(im.compare(im), 0) + im2 = mapnik.Image(2,2,mapnik.ImageType.gray16) + im2.fill(0) + eq_(im.compare(im2), 0) + eq_(im2.compare(im), 0) + eq_(im.compare(im2, 0, False), 0) + im3 = mapnik.Image(2,2,mapnik.ImageType.gray16) + im3.set_pixel(0,0,0) + im3.set_pixel(0,1,1) + im3.set_pixel(1,0,2) + im3.set_pixel(1,1,3) + eq_(im.compare(im3),3) + eq_(im.compare(im3,1),2) + eq_(im.compare(im3,2),1) + eq_(im.compare(im3,3),0) + +def test_compare_gray32f(): + im = mapnik.Image(2,2,mapnik.ImageType.gray32f) + im.fill(0.5) + eq_(im.compare(im), 0) + im2 = mapnik.Image(2,2,mapnik.ImageType.gray32f) + im2.fill(0.5) + eq_(im.compare(im2), 0) + eq_(im2.compare(im), 0) + eq_(im.compare(im2, 0, False), 0) + im3 = mapnik.Image(2,2,mapnik.ImageType.gray32f) + im3.set_pixel(0,0,0.5) + im3.set_pixel(0,1,1.5) + im3.set_pixel(1,0,2.5) + im3.set_pixel(1,1,3.5) + eq_(im.compare(im3),3) + eq_(im.compare(im3,1.0),2) + eq_(im.compare(im3,2.0),1) + eq_(im.compare(im3,3.0),0) + +if __name__ == "__main__": + setup() + exit(run_all(eval(x) for x in dir() if x.startswith("test_"))) diff --git a/tests/python_tests/compositing_test.py b/tests/python_tests/compositing_test.py index f4d4f24f9..08bd3c708 100644 --- a/tests/python_tests/compositing_test.py +++ b/tests/python_tests/compositing_test.py @@ -241,10 +241,10 @@ def test_background_image_with_alpha_and_background_color_against_composited_con mapnik.render(m,im) # create and composite the expected result im1 = mapnik.Image(10,10) - im1.background = mapnik.Color('rgba(255,255,255,.5)') + im1.fill(mapnik.Color('rgba(255,255,255,.5)')) im1.premultiply() im2 = mapnik.Image(10,10) - im2.background = mapnik.Color('rgba(255,255,0,.5)') + im2.fill(mapnik.Color('rgba(255,255,0,.5)')) im2.premultiply() im1.composite(im2) im1.demultiply() diff --git a/tests/python_tests/copy_test.py b/tests/python_tests/copy_test.py new file mode 100644 index 000000000..d3cf9b15c --- /dev/null +++ b/tests/python_tests/copy_test.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os, mapnik +from nose.tools import * +from utilities import execution_path, run_all + +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + +def test_image_16_8_simple(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + im.set_pixel(0,0, 256) + im.set_pixel(0,1, 999) + im.set_pixel(1,0, 5) + im.set_pixel(1,1, 2) + im2 = im.copy(mapnik.ImageType.gray8) + eq_(im2.get_pixel(0,0), 255) + eq_(im2.get_pixel(0,1), 255) + eq_(im2.get_pixel(1,0), 5) + eq_(im2.get_pixel(1,1), 2) + # Cast back! + im = im2.copy(mapnik.ImageType.gray16) + eq_(im.get_pixel(0,0), 255) + eq_(im.get_pixel(0,1), 255) + eq_(im.get_pixel(1,0), 5) + eq_(im.get_pixel(1,1), 2) + +def test_image_32f_8_simple(): + im = mapnik.Image(2,2,mapnik.ImageType.gray32f) + im.set_pixel(0,0, 120.1234) + im.set_pixel(0,1, -23.4) + im.set_pixel(1,0, 120.6) + im.set_pixel(1,1, 360.2) + im2 = im.copy(mapnik.ImageType.gray8) + eq_(im2.get_pixel(0,0), 120) + eq_(im2.get_pixel(0,1), 0) + eq_(im2.get_pixel(1,0), 120) # Notice this is truncated! + eq_(im2.get_pixel(1,1), 255) + +def test_image_offset_and_scale(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + eq_(im.offset, 0.0) + eq_(im.scaling, 1.0) + im.offset = 1.0 + im.scaling = 2.0 + eq_(im.offset, 1.0) + eq_(im.scaling, 2.0) + +def test_image_16_8_scale_and_offset(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + im.set_pixel(0,0, 256) + im.set_pixel(0,1, 258) + im.set_pixel(1,0, 99999) + im.set_pixel(1,1, 615) + offset = 255 + scaling = 3 + im2 = im.copy(mapnik.ImageType.gray8, offset, scaling) + eq_(im2.get_pixel(0,0), 0) + eq_(im2.get_pixel(0,1), 1) + eq_(im2.get_pixel(1,0), 255) + eq_(im2.get_pixel(1,1), 120) + # pixels will be a little off due to offsets in reverting! + im3 = im2.copy(mapnik.ImageType.gray16) + eq_(im3.get_pixel(0,0), 255) # Rounding error with ints + eq_(im3.get_pixel(0,1), 258) # same + eq_(im3.get_pixel(1,0), 1020) # The other one was way out of range for our scale/offset + eq_(im3.get_pixel(1,1), 615) # same + +def test_image_16_32f_scale_and_offset(): + im = mapnik.Image(2,2,mapnik.ImageType.gray16) + im.set_pixel(0,0, 256) + im.set_pixel(0,1, 258) + im.set_pixel(1,0, 0) + im.set_pixel(1,1, 615) + offset = 255 + scaling = 3.2 + im2 = im.copy(mapnik.ImageType.gray32f, offset, scaling) + eq_(im2.get_pixel(0,0), 0.3125) + eq_(im2.get_pixel(0,1), 0.9375) + eq_(im2.get_pixel(1,0), -79.6875) + eq_(im2.get_pixel(1,1), 112.5) + im3 = im2.copy(mapnik.ImageType.gray16) + eq_(im3.get_pixel(0,0), 256) + eq_(im3.get_pixel(0,1), 258) + eq_(im3.get_pixel(1,0), 0) + eq_(im3.get_pixel(1,1), 615) + +if __name__ == "__main__": + setup() + exit(run_all(eval(x) for x in dir() if x.startswith("test_"))) diff --git a/tests/python_tests/datasource_test.py b/tests/python_tests/datasource_test.py index e13d0d248..4ada3dc3c 100644 --- a/tests/python_tests/datasource_test.py +++ b/tests/python_tests/datasource_test.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from nose.tools import eq_ +from nose.tools import eq_, raises from utilities import execution_path, run_all import os, mapnik from itertools import groupby @@ -15,6 +15,7 @@ def test_that_datasources_exist(): print '***NOTICE*** - no datasource plugins have been loaded' # adapted from raster_symboliser_test#test_dataraster_query_point +@raises(RuntimeError) def test_vrt_referring_to_missing_files(): srs = '+init=epsg:32630' if 'gdal' in mapnik.DatasourceCache.plugin_names(): @@ -32,13 +33,26 @@ def test_vrt_referring_to_missing_files(): _map.zoom_all() - # Should RuntimeError here + # Fancy stuff to supress output of error + # open 2 fds + null_fds = [os.open(os.devnull, os.O_RDWR) for x in xrange(2)] + # save the current file descriptors to a tuple + save = os.dup(1), os.dup(2) + # put /dev/null fds on 1 and 2 + os.dup2(null_fds[0], 1) + os.dup2(null_fds[1], 2) + + # *** run the function *** try: + # Should RuntimeError here _map.query_point(0, x, y).features - except RuntimeError, e: - eq_("this_file_should_not_exist.tif' does not exist in the file system" in str(e), True) - else: - assert False + finally: + # restore file descriptors so I can print the results + os.dup2(save[0], 1) + os.dup2(save[1], 2) + # close the temporary fds + os.close(null_fds[0]) + os.close(null_fds[1]) def test_field_listing(): diff --git a/tests/python_tests/grayscale_test.py b/tests/python_tests/grayscale_test.py index f347d7256..2bcf8361b 100644 --- a/tests/python_tests/grayscale_test.py +++ b/tests/python_tests/grayscale_test.py @@ -4,7 +4,7 @@ from utilities import run_all def test_grayscale_conversion(): im = mapnik.Image(2,2) - im.background = mapnik.Color('white') + im.fill(mapnik.Color('white')) im.set_grayscale_to_alpha() pixel = im.get_pixel(0,0) eq_((pixel >> 24) & 0xff,255); diff --git a/tests/python_tests/image_encoding_speed_test.py b/tests/python_tests/image_encoding_speed_test.py index 9ba174853..75bbc85af 100644 --- a/tests/python_tests/image_encoding_speed_test.py +++ b/tests/python_tests/image_encoding_speed_test.py @@ -86,7 +86,7 @@ def do_encoding(): def solid(): return eval('image.tostring("%s")' % c) solid_im = mapnik.Image(512,512) - solid_im.background = mapnik.Color("#f2efe9") + solid_im.fill(mapnik.Color("#f2efe9")) for c in combinations: t = Timer(solid) run(solid,solid_im,c,t) diff --git a/tests/python_tests/image_test.py b/tests/python_tests/image_test.py index 9e9e4b90f..f468c8b09 100644 --- a/tests/python_tests/image_test.py +++ b/tests/python_tests/image_test.py @@ -2,8 +2,8 @@ # -*- coding: utf-8 -*- import os, mapnik -from nose.tools import eq_,raises -from utilities import execution_path, run_all +from nose.tools import eq_,raises, assert_almost_equal +from utilities import execution_path, run_all, get_unique_colors def setup(): # All of the paths used are relative, if we run the tests @@ -13,10 +13,259 @@ def setup(): def test_image_premultiply(): im = mapnik.Image(256,256) eq_(im.premultiplied(),False) - im.premultiply() + # Premultiply should return true that it worked + eq_(im.premultiply(), True) eq_(im.premultiplied(),True) - im.demultiply() + # Premultipling again should return false as nothing should happen + eq_(im.premultiply(), False) + eq_(im.premultiplied(),True) + # Demultiply should return true that it worked + eq_(im.demultiply(), True) eq_(im.premultiplied(),False) + # Demultiply again should not work and return false as it did nothing + eq_(im.demultiply(), False) + eq_(im.premultiplied(),False) + +def test_image_premultiply_values(): + im = mapnik.Image(256,256) + im.fill(mapnik.Color(16, 33, 255, 128)) + im.premultiply() + c = im.get_pixel_color(0,0) + eq_(c.r, 8) + eq_(c.g, 17) + eq_(c.b, 128) + eq_(c.a, 128) + im.demultiply() + # Do to the nature of this operation the result will not be exactly the same + c = im.get_pixel_color(0,0) + eq_(c.r,15) + eq_(c.g,33) + eq_(c.b,255) + eq_(c.a,128) + +def test_background(): + im = mapnik.Image(256,256) + eq_(im.premultiplied(), False) + im.fill(mapnik.Color(32,64,125,128)) + eq_(im.premultiplied(), False) + c = im.get_pixel_color(0,0) + eq_(c.get_premultiplied(), False) + eq_(c.r,32) + eq_(c.g,64) + eq_(c.b,125) + eq_(c.a,128) + # Now again with a premultiplied alpha + im.fill(mapnik.Color(32,64,125,128,True)) + eq_(im.premultiplied(), True) + c = im.get_pixel_color(0,0) + eq_(c.get_premultiplied(), True) + eq_(c.r,32) + eq_(c.g,64) + eq_(c.b,125) + eq_(c.a,128) + +def test_set_and_get_pixel(): + # Create an image that is not premultiplied + im = mapnik.Image(256,256) + c0 = mapnik.Color(16,33,255,128) + c0_pre = mapnik.Color(16,33,255,128, True) + im.set_pixel(0,0,c0) + im.set_pixel(1,1,c0_pre) + # No differences for non premultiplied pixels + c1_int = mapnik.Color(im.get_pixel(0,0)) + eq_(c0.r, c1_int.r) + eq_(c0.g, c1_int.g) + eq_(c0.b, c1_int.b) + eq_(c0.a, c1_int.a) + c1 = im.get_pixel_color(0,0) + eq_(c0.r, c1.r) + eq_(c0.g, c1.g) + eq_(c0.b, c1.b) + eq_(c0.a, c1.a) + # The premultiplied Color should be demultiplied before being applied. + c0_pre.demultiply() + c1_int = mapnik.Color(im.get_pixel(1,1)) + eq_(c0_pre.r, c1_int.r) + eq_(c0_pre.g, c1_int.g) + eq_(c0_pre.b, c1_int.b) + eq_(c0_pre.a, c1_int.a) + c1 = im.get_pixel_color(1,1) + eq_(c0_pre.r, c1.r) + eq_(c0_pre.g, c1.g) + eq_(c0_pre.b, c1.b) + eq_(c0_pre.a, c1.a) + + # Now create a new image that is premultiplied + im = mapnik.Image(256,256, mapnik.ImageType.rgba8, True, True) + c0 = mapnik.Color(16,33,255,128) + c0_pre = mapnik.Color(16,33,255,128, True) + im.set_pixel(0,0,c0) + im.set_pixel(1,1,c0_pre) + # It should have put pixels that are the same as premultiplied so premultiply c0 + c0.premultiply() + c1_int = mapnik.Color(im.get_pixel(0,0)) + eq_(c0.r, c1_int.r) + eq_(c0.g, c1_int.g) + eq_(c0.b, c1_int.b) + eq_(c0.a, c1_int.a) + c1 = im.get_pixel_color(0,0) + eq_(c0.r, c1.r) + eq_(c0.g, c1.g) + eq_(c0.b, c1.b) + eq_(c0.a, c1.a) + # The premultiplied Color should be the same though + c1_int = mapnik.Color(im.get_pixel(1,1)) + eq_(c0_pre.r, c1_int.r) + eq_(c0_pre.g, c1_int.g) + eq_(c0_pre.b, c1_int.b) + eq_(c0_pre.a, c1_int.a) + c1 = im.get_pixel_color(1,1) + eq_(c0_pre.r, c1.r) + eq_(c0_pre.g, c1.g) + eq_(c0_pre.b, c1.b) + eq_(c0_pre.a, c1.a) + +def test_pixel_gray8(): + im = mapnik.Image(4,4,mapnik.ImageType.gray8) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), 0) + +def test_pixel_gray8s(): + im = mapnik.Image(4,4,mapnik.ImageType.gray8s) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), -v) + +def test_pixel_gray16(): + im = mapnik.Image(4,4,mapnik.ImageType.gray16) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), 0) + +def test_pixel_gray16s(): + im = mapnik.Image(4,4,mapnik.ImageType.gray16s) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), -v) + +def test_pixel_gray32(): + im = mapnik.Image(4,4,mapnik.ImageType.gray32) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), 0) + +def test_pixel_gray32s(): + im = mapnik.Image(4,4,mapnik.ImageType.gray32s) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), -v) + +def test_pixel_gray64(): + im = mapnik.Image(4,4,mapnik.ImageType.gray64) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), 0) + +def test_pixel_gray64s(): + im = mapnik.Image(4,4,mapnik.ImageType.gray64s) + val_list = range(20) + for v in val_list: + im.set_pixel(0,0, v) + eq_(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + eq_(im.get_pixel(0,0), -v) + +def test_pixel_floats(): + im = mapnik.Image(4,4,mapnik.ImageType.gray32f) + val_list = [0.9, 0.99, 0.999, 0.9999, 0.99999, 1, 1.0001, 1.001, 1.01, 1.1] + for v in val_list: + im.set_pixel(0,0, v) + assert_almost_equal(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + assert_almost_equal(im.get_pixel(0,0), -v) + +def test_pixel_doubles(): + im = mapnik.Image(4,4,mapnik.ImageType.gray64f) + val_list = [0.9, 0.99, 0.999, 0.9999, 0.99999, 1, 1.0001, 1.001, 1.01, 1.1] + for v in val_list: + im.set_pixel(0,0, v) + assert_almost_equal(im.get_pixel(0,0), v) + im.set_pixel(0,0, -v) + assert_almost_equal(im.get_pixel(0,0), -v) + +def test_pixel_overflow(): + im = mapnik.Image(4,4,mapnik.ImageType.gray8) + im.set_pixel(0,0,256) + eq_(im.get_pixel(0,0),255) + +def test_pixel_underflow(): + im = mapnik.Image(4,4,mapnik.ImageType.gray8) + im.set_pixel(0,0,-1) + eq_(im.get_pixel(0,0),0) + im = mapnik.Image(4,4,mapnik.ImageType.gray16) + im.set_pixel(0,0,-1) + eq_(im.get_pixel(0,0),0) + +@raises(IndexError) +def test_set_pixel_out_of_range_1(): + im = mapnik.Image(4,4) + c = mapnik.Color('blue') + im.set_pixel(5,5,c) + +@raises(OverflowError) +def test_set_pixel_out_of_range_2(): + im = mapnik.Image(4,4) + c = mapnik.Color('blue') + im.set_pixel(-1,1,c) + +@raises(IndexError) +def test_get_pixel_out_of_range_1(): + im = mapnik.Image(4,4) + c = im.get_pixel(5,5) + +@raises(OverflowError) +def test_get_pixel_out_of_range_2(): + im = mapnik.Image(4,4) + c = im.get_pixel(-1,1) + +@raises(IndexError) +def test_get_pixel_color_out_of_range_1(): + im = mapnik.Image(4,4) + c = im.get_pixel_color(5,5) + +@raises(OverflowError) +def test_get_pixel_color_out_of_range_2(): + im = mapnik.Image(4,4) + c = im.get_pixel_color(-1,1) + +def test_set_color_to_alpha(): + im = mapnik.Image(256,256) + im.fill(mapnik.Color('rgba(12,12,12,255)')) + eq_(get_unique_colors(im), ['rgba(12,12,12,255)']) + im.set_color_to_alpha(mapnik.Color('rgba(12,12,12,0)')) + eq_(get_unique_colors(im), ['rgba(0,0,0,0)']) @raises(RuntimeError) def test_negative_image_dimensions(): @@ -29,7 +278,7 @@ def test_negative_image_dimensions(): def test_jpeg_round_trip(): filepath = '/tmp/mapnik-jpeg-io.jpeg' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.fill(mapnik.Color('rgba(1,2,3,.5)')) im.save(filepath,'jpeg') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -45,7 +294,7 @@ def test_jpeg_round_trip(): def test_png_round_trip(): filepath = '/tmp/mapnik-png-io.png' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.fill(mapnik.Color('rgba(1,2,3,.5)')) im.save(filepath,'png') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) diff --git a/tests/python_tests/image_tiff_test.py b/tests/python_tests/image_tiff_test.py index a30668fc5..d8e4f6c1c 100644 --- a/tests/python_tests/image_tiff_test.py +++ b/tests/python_tests/image_tiff_test.py @@ -2,9 +2,13 @@ # -*- coding: utf-8 -*- import os, mapnik -from nose.tools import eq_ +import hashlib +from nose.tools import eq_, assert_not_equal from utilities import execution_path, run_all +def hashstr(var): + return hashlib.md5(var).hexdigest() + def setup(): # All of the paths used are relative, if we run the tests # from another directory we need to chdir() @@ -13,8 +17,8 @@ def setup(): def test_tiff_round_trip_scanline(): filepath = '/tmp/mapnik-tiff-io-scanline.tiff' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') - org_str = len(im.tostring()) + im.fill(mapnik.Color('rgba(12,255,128,.5)')) + org_str = hashstr(im.tostring()) im.save(filepath,'tiff:method=scanline') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -22,74 +26,121 @@ def test_tiff_round_trip_scanline(): eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()), org_str) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im3.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()), org_str) + # This won't be the same the first time around because the im is not premultiplied and im2 is + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) + # Now premultiply + im.premultiply() + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) + eq_(hashstr(im2.tostring('tiff:method=scanline')),hashstr(im3.tostring('tiff:method=scanline'))) def test_tiff_round_trip_stripped(): filepath = '/tmp/mapnik-tiff-io-stripped.tiff' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') - org_str = len(im.tostring()) + im.fill(mapnik.Color('rgba(12,255,128,.5)')) + org_str = hashstr(im.tostring()) im.save(filepath,'tiff:method=stripped') im2 = mapnik.Image.open(filepath) + im2.save('/tmp/mapnik-tiff-io-stripped2.tiff','tiff:method=stripped') im3 = mapnik.Image.fromstring(open(filepath,'r').read()) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()), org_str) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im3.tostring('tiff:method=stripped'))) + # Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the + # difference in tags. + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) + # Now if we premultiply they will be exactly the same + im.premultiply() + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) + # Both of these started out premultiplied, so this round trip should be exactly the same! + eq_(hashstr(im2.tostring('tiff:method=stripped')),hashstr(im3.tostring('tiff:method=stripped'))) def test_tiff_round_trip_rows_stripped(): - filepath = '/tmp/mapnik-tiff-io-stripped.tiff' + filepath = '/tmp/mapnik-tiff-io-rows_stripped.tiff' + filepath2 = '/tmp/mapnik-tiff-io-rows_stripped2.tiff' im = mapnik.Image(255,267) - im.background = mapnik.Color('rgba(1,2,3,.5)') - org_str = len(im.tostring()) + im.fill(mapnik.Color('rgba(12,255,128,.5)')) + c = im.get_pixel_color(0,0) + eq_(c.r, 12) + eq_(c.g, 255) + eq_(c.b, 128) + eq_(c.a, 128) + eq_(c.get_premultiplied(), False) im.save(filepath,'tiff:method=stripped:rows_per_strip=8') im2 = mapnik.Image.open(filepath) + c2 = im2.get_pixel_color(0,0) + eq_(c2.r, 6) + eq_(c2.g, 128) + eq_(c2.b, 64) + eq_(c2.a, 128) + eq_(c2.get_premultiplied(), True) + im2.save(filepath2,'tiff:method=stripped:rows_per_strip=8') im3 = mapnik.Image.fromstring(open(filepath,'r').read()) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()), org_str) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped:rows_per_strip=8')),len(im2.tostring('tiff:method=stripped:rows_per_strip=8'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=stripped:rows_per_strip=8')),len(im3.tostring('tiff:method=stripped:rows_per_strip=8'))) + # Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the + # difference in tags. + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8'))) + # Now premultiply the first image and they will be the same! + im.premultiply() + eq_(hashstr(im.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) + # Both of these started out premultiplied, so this round trip should be exactly the same! + eq_(hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im3.tostring('tiff:method=stripped:rows_per_strip=8'))) def test_tiff_round_trip_buffered_tiled(): filepath = '/tmp/mapnik-tiff-io-buffered-tiled.tiff' filepath2 = '/tmp/mapnik-tiff-io-buffered-tiled2.tiff' + filepath3 = '/tmp/mapnik-tiff-io-buffered-tiled3.tiff' im = mapnik.Image(255,267) - #im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.fill(mapnik.Color('rgba(33,255,128,.5)')) + c = im.get_pixel_color(0,0) + eq_(c.r, 33) + eq_(c.g, 255) + eq_(c.b, 128) + eq_(c.a, 128) + eq_(c.get_premultiplied(), False) im.save(filepath,'tiff:method=tiled:tile_width=32:tile_height=32') im2 = mapnik.Image.open(filepath) + c2 = im2.get_pixel_color(0,0) + eq_(c2.r, 17) + eq_(c2.g, 128) + eq_(c2.b, 64) + eq_(c2.a, 128) + eq_(c2.get_premultiplied(), True) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) im2.save(filepath2, 'tiff:method=tiled:tile_width=32:tile_height=32') - im4 = mapnik.Image.open(filepath2) + im3.save(filepath3, 'tiff:method=tiled:tile_width=32:tile_height=32') eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im2.tostring()),len(im4.tostring())) - eq_(len(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im4.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),len(im3.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) + # Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the + # difference in tags. + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) + # Now premultiply the first image and they should be the same + im.premultiply() + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) + # Both of these started out premultiplied, so this round trip should be exactly the same! + eq_(hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im3.tostring('tiff:method=tiled:tile_width=32:tile_height=32'))) def test_tiff_round_trip_tiled(): filepath = '/tmp/mapnik-tiff-io-tiled.tiff' im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(1,2,3,.5)') + im.fill(mapnik.Color('rgba(1,255,128,.5)')) im.save(filepath,'tiff:method=tiled') im2 = mapnik.Image.open(filepath) im3 = mapnik.Image.fromstring(open(filepath,'r').read()) @@ -97,10 +148,17 @@ def test_tiff_round_trip_tiled(): eq_(im.height(),im2.height()) eq_(im.width(),im3.width()) eq_(im.height(),im3.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) - eq_(len(im.tostring()),len(im3.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im3.tostring('tiff:method=tiled'))) + # Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the + # difference in tags. + assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring())) + assert_not_equal(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) + # Now premultiply the first image and they will be exactly the same. + im.premultiply() + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im2.tostring()),hashstr(im3.tostring())) + # Both of these started out premultiplied, so this round trip should be exactly the same! + eq_(hashstr(im2.tostring('tiff:method=tiled')),hashstr(im3.tostring('tiff:method=tiled'))) def test_tiff_rgb8_compare(): @@ -111,10 +169,10 @@ def test_tiff_rgb8_compare(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff')),len(im2.tostring('tiff'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff')),hashstr(im2.tostring('tiff'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -124,10 +182,10 @@ def test_tiff_rgba8_compare_scanline(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -137,10 +195,10 @@ def test_tiff_rgba8_compare_stripped(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_rgba8_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif' @@ -150,10 +208,10 @@ def test_tiff_rgba8_compare_tiled(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) # should not be a blank image - eq_(len(im.tostring("png")) != len(mapnik.Image(im.width(),im.height()).tostring("png")),True) + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True) def test_tiff_gray8_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -163,8 +221,10 @@ def test_tiff_gray8_compare_scanline(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray8_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -174,8 +234,10 @@ def test_tiff_gray8_compare_stripped(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray8_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif' @@ -185,8 +247,10 @@ def test_tiff_gray8_compare_tiled(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True) def test_tiff_gray16_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -196,8 +260,10 @@ def test_tiff_gray16_compare_scanline(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray16_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -207,8 +273,10 @@ def test_tiff_gray16_compare_stripped(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray16_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif' @@ -218,8 +286,10 @@ def test_tiff_gray16_compare_tiled(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True) def test_tiff_gray32f_compare_scanline(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -229,8 +299,10 @@ def test_tiff_gray32f_compare_scanline(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=scanline')),len(im2.tostring('tiff:method=scanline'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) def test_tiff_gray32f_compare_stripped(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -240,8 +312,10 @@ def test_tiff_gray32f_compare_stripped(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=stripped')),len(im2.tostring('tiff:method=stripped'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) def test_tiff_gray32f_compare_tiled(): filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif' @@ -251,8 +325,10 @@ def test_tiff_gray32f_compare_tiled(): im2 = mapnik.Image.open(filepath2) eq_(im.width(),im2.width()) eq_(im.height(),im2.height()) - eq_(len(im.tostring()),len(im2.tostring())) - eq_(len(im.tostring('tiff:method=tiled')),len(im2.tostring('tiff:method=tiled'))) + eq_(hashstr(im.tostring()),hashstr(im2.tostring())) + eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled'))) + # should not be a blank image + eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True) if __name__ == "__main__": setup() diff --git a/tests/python_tests/images/actual.png b/tests/python_tests/images/actual.png new file mode 100644 index 000000000..adfa8568b Binary files /dev/null and b/tests/python_tests/images/actual.png differ diff --git a/tests/python_tests/images/expected.png b/tests/python_tests/images/expected.png new file mode 100644 index 000000000..5a27b46ee Binary files /dev/null and b/tests/python_tests/images/expected.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_16bsi_subquery-16BSI-135.png b/tests/python_tests/images/support/pgraster/data_subquery-data_16bsi_subquery-16BSI-135.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_16bsi_subquery-16BSI-135.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_16bui_subquery-16BUI-126.png b/tests/python_tests/images/support/pgraster/data_subquery-data_16bui_subquery-16BUI-126.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_16bui_subquery-16BUI-126.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_2bui_subquery-2BUI-3.png b/tests/python_tests/images/support/pgraster/data_subquery-data_2bui_subquery-2BUI-3.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_2bui_subquery-2BUI-3.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_32bf_subquery-32BF-450.png b/tests/python_tests/images/support/pgraster/data_subquery-data_32bf_subquery-32BF-450.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_32bf_subquery-32BF-450.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_32bsi_subquery-32BSI-264.png b/tests/python_tests/images/support/pgraster/data_subquery-data_32bsi_subquery-32BSI-264.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_32bsi_subquery-32BSI-264.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_32bui_subquery-32BUI-255.png b/tests/python_tests/images/support/pgraster/data_subquery-data_32bui_subquery-32BUI-255.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_32bui_subquery-32BUI-255.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_4bui_subquery-4BUI-15.png b/tests/python_tests/images/support/pgraster/data_subquery-data_4bui_subquery-4BUI-15.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_4bui_subquery-4BUI-15.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_64bf_subquery-64BF-3072.png b/tests/python_tests/images/support/pgraster/data_subquery-data_64bf_subquery-64BF-3072.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_64bf_subquery-64BF-3072.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_8bsi_subquery-8BSI-69.png b/tests/python_tests/images/support/pgraster/data_subquery-data_8bsi_subquery-8BSI-69.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_8bsi_subquery-8BSI-69.png differ diff --git a/tests/python_tests/images/support/pgraster/data_subquery-data_8bui_subquery-8BUI-63.png b/tests/python_tests/images/support/pgraster/data_subquery-data_8bui_subquery-8BUI-63.png new file mode 100644 index 000000000..e6fad0d0b Binary files /dev/null and b/tests/python_tests/images/support/pgraster/data_subquery-data_8bui_subquery-8BUI-63.png differ diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_16bsi_subquery-16BSI-144.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_16bsi_subquery-16BSI-144.png new file mode 100644 index 000000000..719c7e045 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_16bsi_subquery-16BSI-144.png differ diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_16bui_subquery-16BUI-126.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_16bui_subquery-16BUI-126.png new file mode 100644 index 000000000..a6aa1a65d Binary files /dev/null and b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_16bui_subquery-16BUI-126.png differ diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_2bui_subquery-2BUI-3.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_2bui_subquery-2BUI-3.png new file mode 100644 index 000000000..62aa1631a Binary files /dev/null and b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_2bui_subquery-2BUI-3.png differ diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bsi_subquery-32BSI-129.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bsi_subquery-32BSI-129.png new file mode 100644 index 000000000..b134b2d24 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bsi_subquery-32BSI-129.png differ diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bui_subquery-32BUI-255.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bui_subquery-32BUI-255.png new file mode 100644 index 000000000..5f8035a2d Binary files /dev/null and b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_32bui_subquery-32BUI-255.png differ diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_4bui_subquery-4BUI-15.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_4bui_subquery-4BUI-15.png new file mode 100644 index 000000000..2667c0663 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_4bui_subquery-4BUI-15.png differ diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bsi_subquery-8BSI-69.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bsi_subquery-8BSI-69.png new file mode 100644 index 000000000..85abadd9e Binary files /dev/null and b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bsi_subquery-8BSI-69.png differ diff --git a/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bui_subquery-8BUI-63.png b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bui_subquery-8BUI-63.png new file mode 100644 index 000000000..06d6249a2 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/grayscale_subquery-grayscale_8bui_subquery-8BUI-63.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box1.png new file mode 100644 index 000000000..cae620513 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box2.png new file mode 100644 index 000000000..846981baa Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Cl--1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc Cl--1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc Cl--1-box1.png new file mode 100644 index 000000000..4fdf9ffbc Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc Cl--1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc Cl--1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc Cl--1-box2.png new file mode 100644 index 000000000..846981baa Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc Cl--1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc--0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc--0-box1.png new file mode 100644 index 000000000..4fdf9ffbc Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc--0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc--0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc--0-box2.png new file mode 100644 index 000000000..846981baa Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64 Sc--0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box1.png new file mode 100644 index 000000000..cae620513 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box2.png new file mode 100644 index 000000000..846981baa Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-nodataedge-rgb_8bui C T:64x64--0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box2.png new file mode 100644 index 000000000..0669f5288 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Cl-2-1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box2.png new file mode 100644 index 000000000..0669f5288 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc Cl-2-1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box2.png new file mode 100644 index 000000000..04135187e Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2 Sc-2-0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box2.png new file mode 100644 index 000000000..04135187e Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C O:2-2-0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box2.png new file mode 100644 index 000000000..62e35be30 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Cl-2-1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box2.png new file mode 100644 index 000000000..62e35be30 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc Cl-2-1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box2.png new file mode 100644 index 000000000..5460a3836 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2 Sc-2-0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box2.png new file mode 100644 index 000000000..5460a3836 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui C T:16x16 O:2-2-0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png new file mode 100644 index 000000000..0669f5288 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Cl-2-1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png new file mode 100644 index 000000000..0669f5288 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc Cl-2-1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png new file mode 100644 index 000000000..04135187e Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2 Sc-2-0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box2.png new file mode 100644 index 000000000..04135187e Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui O:2-2-0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png new file mode 100644 index 000000000..62e35be30 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Cl-2-1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png new file mode 100644 index 000000000..62e35be30 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc Cl-2-1-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png new file mode 100644 index 000000000..5460a3836 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2 Sc-2-0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png new file mode 100644 index 000000000..981cf74df Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box1.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png new file mode 100644 index 000000000..5460a3836 Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_8bui-rgba_8bui T:16x16 O:2-2-0-box2.png differ diff --git a/tests/python_tests/images/support/pgraster/rgba_subquery-rgba_8bui_subquery-8BUI-255-0-0-255-255-255.png b/tests/python_tests/images/support/pgraster/rgba_subquery-rgba_8bui_subquery-8BUI-255-0-0-255-255-255.png new file mode 100644 index 000000000..d83016d2a Binary files /dev/null and b/tests/python_tests/images/support/pgraster/rgba_subquery-rgba_8bui_subquery-8BUI-255-0-0-255-255-255.png differ diff --git a/tests/python_tests/pgraster_test.py b/tests/python_tests/pgraster_test.py index f635f8d5f..fa5dd0bb1 100644 --- a/tests/python_tests/pgraster_test.py +++ b/tests/python_tests/pgraster_test.py @@ -3,14 +3,13 @@ from nose.tools import eq_,assert_almost_equal import atexit import time -from utilities import execution_path, run_all +from utilities import execution_path, run_all, side_by_side_image from subprocess import Popen, PIPE import os, mapnik import sys import re from binascii import hexlify - MAPNIK_TEST_DBNAME = 'mapnik-tmp-pgraster-test-db' POSTGIS_TEMPLATE_DBNAME = 'template_postgis' DEBUG_OUTPUT=False @@ -110,6 +109,20 @@ def drop_imported(tabname, overview): for of in overview.split(','): psql_run('DROP TABLE IF EXISTS "o_' + of + '_' + tabname + '";') +def compare_images(expected,im): + if not os.path.exists(expected) or os.environ.get('UPDATE'): + print 'generating expected image %s' % expected + im.save(expected,'png32') + expected_im = mapnik.Image.open(expected) + diff = expected.replace('.png','-diff.png') + if len(im.tostring("png32")) != len(expected_im.tostring("png32")): + compared = side_by_side_image(expected_im, im) + compared.save(diff) + assert False,'images do not match, check diff at %s' % diff + else: + if os.path.exists(diff): os.unlink(diff) + return True + if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ and createdb_and_dropdb_on_path() \ and psql_can_connect() \ @@ -268,7 +281,8 @@ if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') - #im.save('/tmp/xfull.png') # for debugging + expected = 'images/support/pgraster/%s-%s-%s-%s-box1.png' % (lyr.name,lbl,overview,clip) + compare_images(expected,im) # no data eq_(hexlify(im.view(3,3,1,1).tostring()), '00000000') eq_(hexlify(im.view(250,250,1,1).tostring()), '00000000') @@ -287,10 +301,12 @@ if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ newenv = mapnik.Box2d(166,-105,191,-77) mm.zoom_to_box(newenv) t0 = time.time() # we want wall time to include IO waits + im = mapnik.Image(mm.width, mm.height) mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:1/10') - #im.save('/tmp/xtenth.png') # for debugging + expected = 'images/support/pgraster/%s-%s-%s-%s-box2.png' % (lyr.name,lbl,overview,clip) + compare_images(expected,im) # no data eq_(hexlify(im.view(255,255,1,1).tostring()), '00000000') eq_(hexlify(im.view(200,40,1,1).tostring()), '00000000') @@ -369,7 +385,8 @@ if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') - #im.save('/tmp/xfull.png') # for debugging + expected = 'images/support/pgraster/%s-%s-%s-%s-%s-box1.png' % (lyr.name,tnam,lbl,overview,clip) + compare_images(expected,im) # no data eq_(hexlify(im.view(3,16,1,1).tostring()), '00000000') eq_(hexlify(im.view(128,16,1,1).tostring()), '00000000') @@ -386,10 +403,12 @@ if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ -12328997.49148983,4508957.34625536) mm.zoom_to_box(newenv) t0 = time.time() # we want wall time to include IO waits + im = mapnik.Image(mm.width, mm.height) mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:1/10') - #im.save('/tmp/xtenth.png') # for debugging + expected = 'images/support/pgraster/%s-%s-%s-%s-%s-box2.png' % (lyr.name,tnam,lbl,overview,clip) + compare_images(expected,im) # no data eq_(hexlify(im.view(3,16,1,1).tostring()), '00000000') eq_(hexlify(im.view(128,16,1,1).tostring()), '00000000') @@ -483,7 +502,8 @@ if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') - #im.save('/tmp/xfull.png') # for debugging + expected = 'images/support/pgraster/%s-%s-%s-%s.png' % (lyr.name,lbl,pixtype,value) + compare_images(expected,im) h = format(value, '02x') hex_v = h+h+h+'ff' h = format(val_a, '02x') @@ -597,6 +617,8 @@ if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') + expected = 'images/support/pgraster/%s-%s-%s-%s.png' % (lyr.name,lbl,pixtype,value) + compare_images(expected,im) def test_data_2bui_subquery(): _test_data_subquery('data_2bui_subquery', '2BUI', 3) @@ -702,7 +724,8 @@ if 'pgraster' in mapnik.DatasourceCache.plugin_names() \ mapnik.render(mm, im) lap = time.time() - t0 log('T ' + str(lap) + ' -- ' + lbl + ' E:full') - im.save('/tmp/xfull.png') # for debugging + expected = 'images/support/pgraster/%s-%s-%s-%s-%s-%s-%s-%s-%s.png' % (lyr.name,lbl, pixtype, r, g, b, a, g1, b1) + compare_images(expected,im) hex_v = format(r << 24 | g << 16 | b << 8 | a, '08x') hex_a = format(r << 24 | g1 << 16 | b << 8 | a, '08x') hex_b = format(r << 24 | g << 16 | b1 << 8 | a, '08x') diff --git a/tests/python_tests/png_encoding_test.py b/tests/python_tests/png_encoding_test.py index 27c7f1f2f..568edfd78 100644 --- a/tests/python_tests/png_encoding_test.py +++ b/tests/python_tests/png_encoding_test.py @@ -59,7 +59,7 @@ if mapnik.has_png(): '%s (actual) not == to %s (expected)' % (actual,expected)) # solid image - im.background = mapnik.Color('green'); + im.fill(mapnik.Color('green')) for opt in opts: expected = gen_filepath('blank',opt) actual = os.path.join(tmp_dir,os.path.basename(expected)) @@ -89,7 +89,7 @@ if mapnik.has_png(): def test_transparency_levels(): # create partial transparency image im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(255,255,255,.5)') + im.fill(mapnik.Color('rgba(255,255,255,.5)')) c2 = mapnik.Color('rgba(255,255,0,.2)') c3 = mapnik.Color('rgb(0,255,255)') for y in range(0,im.height()/2): diff --git a/tests/python_tests/render_test.py b/tests/python_tests/render_test.py index 393b3896a..7ac15b4fa 100644 --- a/tests/python_tests/render_test.py +++ b/tests/python_tests/render_test.py @@ -24,7 +24,7 @@ def test_simplest_render(): def test_render_image_to_string(): im = mapnik.Image(256, 256) - im.background = mapnik.Color('black') + im.fill(mapnik.Color('black')) eq_(im.painted(),False) eq_(im.is_solid(),True) s = im.tostring() @@ -32,7 +32,7 @@ def test_render_image_to_string(): def test_non_solid_image(): im = mapnik.Image(256, 256) - im.background = mapnik.Color('black') + im.fill(mapnik.Color('black')) eq_(im.painted(),False) eq_(im.is_solid(),True) # set one pixel to a different color @@ -42,7 +42,7 @@ def test_non_solid_image(): def test_non_solid_image_view(): im = mapnik.Image(256, 256) - im.background = mapnik.Color('black') + im.fill(mapnik.Color('black')) view = im.view(0,0,256,256) eq_(view.is_solid(),True) # set one pixel to a different color @@ -60,13 +60,13 @@ def test_setting_alpha(): im1 = mapnik.Image(w,h) # white, half transparent c1 = mapnik.Color('rgba(255,255,255,.5)') - im1.background = c1 + im1.fill(c1) eq_(im1.painted(),False) eq_(im1.is_solid(),True) # pure white im2 = mapnik.Image(w,h) c2 = mapnik.Color('rgba(255,255,255,1)') - im2.background = c2 + im2.fill(c2) im2.set_alpha(c1.a/255.0) eq_(im2.painted(),False) eq_(im2.is_solid(),True) @@ -74,7 +74,7 @@ def test_setting_alpha(): def test_render_image_to_file(): im = mapnik.Image(256, 256) - im.background = mapnik.Color('black') + im.fill(mapnik.Color('black')) if mapnik.has_jpeg(): im.save('test.jpg') im.save('test.png', 'png') diff --git a/tests/python_tests/utilities.py b/tests/python_tests/utilities.py index 9893dc4e6..fe02c7d63 100644 --- a/tests/python_tests/utilities.py +++ b/tests/python_tests/utilities.py @@ -7,6 +7,8 @@ from nose.tools import assert_almost_equal import os, sys, traceback import mapnik +HERE = os.path.dirname(__file__) + def execution_path(filename): return os.path.join(os.path.dirname(sys._getframe(1).f_code.co_filename), filename) @@ -84,8 +86,12 @@ def side_by_side_image(left_im, right_im): width = left_im.width() + 1 + right_im.width() height = max(left_im.height(), right_im.height()) im = mapnik.Image(width, height) - im.blend(0, 0, left_im, 1.0) - im.blend(left_im.width() + 1, 0, right_im, 1.0) + im.composite(left_im,mapnik.CompositeOp.src_over,1.0,0,0) + if width > 80: + im.composite(mapnik.Image.open(HERE+'/images/expected.png'),mapnik.CompositeOp.difference,1.0,0,0) + im.composite(right_im,mapnik.CompositeOp.src_over,1.0,left_im.width() + 1, 0) + if width > 80: + im.composite(mapnik.Image.open(HERE+'/images/actual.png'),mapnik.CompositeOp.difference,1.0,left_im.width() + 1, 0) return im def assert_box2d_almost_equal(a, b, msg=None): diff --git a/tests/python_tests/webp_encoding_test.py b/tests/python_tests/webp_encoding_test.py index 12f75e57d..f14bfc490 100644 --- a/tests/python_tests/webp_encoding_test.py +++ b/tests/python_tests/webp_encoding_test.py @@ -82,7 +82,7 @@ if mapnik.has_webp(): for opt in opts: im = mapnik.Image(256,256) - im.background = mapnik.Color('green') + im.fill(mapnik.Color('green')) expected = gen_filepath('solid',opt) actual = os.path.join(tmp_dir,os.path.basename(expected)) if generate or not os.path.exists(expected): @@ -123,7 +123,7 @@ if mapnik.has_webp(): try: # create partial transparency image im = mapnik.Image(256,256) - im.background = mapnik.Color('rgba(255,255,255,.5)') + im.fill(mapnik.Color('rgba(255,255,255,.5)')) c2 = mapnik.Color('rgba(255,255,0,.2)') c3 = mapnik.Color('rgb(0,255,255)') for y in range(0,im.height()/2): diff --git a/tests/visual_tests/compare.py b/tests/visual_tests/compare.py index e1b72893c..aa95d33ae 100644 --- a/tests/visual_tests/compare.py +++ b/tests/visual_tests/compare.py @@ -33,17 +33,17 @@ def compare_pixels(pixel1, pixel2, alpha=True, pixel_threshold=0): def compare(actual, expected, alpha=True): im1 = mapnik.Image.open(actual) im2 = mapnik.Image.open(expected) - diff = 0 pixels = im1.width() * im1.height() delta_pixels = (im2.width() * im2.height()) - pixels + #diff = 0 if delta_pixels != 0: return delta_pixels - # TODO: convert to C++ to speed this up - for x in range(0,im1.width(),2): - for y in range(0,im1.height(),2): - if compare_pixels(im1.get_pixel(x,y),im2.get_pixel(x,y),alpha=alpha): - diff += 1 - return diff + #for x in range(0,im1.width(),2): + # for y in range(0,im1.height(),2): + # if compare_pixels(im1.get_pixel(x,y),im2.get_pixel(x,y),alpha=alpha): + # diff += 1 + #return diff + return im1.compare(im2, 0, alpha) def compare_grids(actual, expected, threshold=0, alpha=True): global errors diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-agg-reference.png index 699b71c07..54cc50b79 100644 Binary files a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-agg-reference.png and b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-cairo-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-cairo-reference.png index 64108e381..8aadeb581 100644 Binary files a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-cairo-reference.png and b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-agg-reference.png index 699b71c07..54cc50b79 100644 Binary files a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-agg-reference.png and b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-cairo-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-cairo-reference.png index 64108e381..8aadeb581 100644 Binary files a/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-cairo-reference.png and b/tests/visual_tests/images/tiff-opaque-edge-raster2-600-400-2.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-agg-reference.png index b23e716ab..828cdce7c 100644 Binary files a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-agg-reference.png and b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-agg-reference.png differ diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-cairo-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-cairo-reference.png index b23e716ab..828cdce7c 100644 Binary files a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-cairo-reference.png and b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-1.0-cairo-reference.png differ diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-agg-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-agg-reference.png index b23e716ab..828cdce7c 100644 Binary files a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-agg-reference.png and b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-agg-reference.png differ diff --git a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-cairo-reference.png b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-cairo-reference.png index b23e716ab..828cdce7c 100644 Binary files a/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-cairo-reference.png and b/tests/visual_tests/images/tiff-opaque-edge-raster2-969-793-2.0-cairo-reference.png differ diff --git a/utils/nik2img/nik2img.cpp b/utils/nik2img/nik2img.cpp index fe410be7f..1d11358df 100644 --- a/utils/nik2img/nik2img.cpp +++ b/utils/nik2img/nik2img.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -111,7 +110,7 @@ int main (int argc,char** argv) mapnik::Map map(600,400); mapnik::load_map(map,xml_file,true); map.zoom_all(); - mapnik::image_32 im(map.width(),map.height()); + mapnik::image_rgba8 im(map.width(),map.height()); mapnik::request req(map.width(),map.height(),map.get_current_extent()); req.set_buffer_size(map.buffer_size()); mapnik::attributes vars; @@ -138,9 +137,9 @@ int main (int argc,char** argv) } } } - mapnik::agg_renderer ren(map,req,vars,im,scale_factor,0,0); + mapnik::agg_renderer ren(map,req,vars,im,scale_factor,0,0); ren.apply(); - mapnik::save_to_file(im.data(),img_file); + mapnik::save_to_file(im,img_file); if (auto_open) { std::ostringstream s; diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index ab3c6285b..c81392710 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -51,6 +50,92 @@ #include // for xmlInitParser(), xmlCleanupParser() +struct main_marker_visitor +{ + main_marker_visitor(std::string & svg_name, + int & return_value, + bool verbose, + bool auto_open) + : svg_name_(svg_name), + return_value_(return_value), + verbose_(verbose), + auto_open_(auto_open) {} + + void operator() (mapnik::marker_null const&) + { + std::clog << "svg2png error: '" << svg_name_ << "' is not a valid vector!\n"; + return_value_ = -1; + } + + void operator() (mapnik::marker_rgba8 const&) + { + std::clog << "svg2png error: '" << svg_name_ << "' is not a valid vector!\n"; + return_value_ = -1; + } + + void operator() (mapnik::marker_svg const& marker) + { + using pixfmt = agg::pixfmt_rgba32_pre; + using renderer_base = agg::renderer_base; + using renderer_solid = agg::renderer_scanline_aa_solid; + agg::rasterizer_scanline_aa<> ras_ptr; + agg::scanline_u8 sl; + + double opacity = 1; + int w = marker.width(); + int h = marker.height(); + if (verbose_) + { + std::clog << "found width of '" << w << "' and height of '" << h << "'\n"; + } + // 10 pixel buffer to avoid edge clipping of 100% svg's + mapnik::image_rgba8 im(w+0,h+0); + agg::rendering_buffer buf(im.getBytes(), im.width(), im.height(), im.getRowSize()); + pixfmt pixf(buf); + renderer_base renb(pixf); + + mapnik::box2d const& bbox = marker.get_data()->bounding_box(); + mapnik::coord c = bbox.center(); + // center the svg marker on '0,0' + agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); + // render the marker at the center of the marker box + mtx.translate(0.5 * im.width(), 0.5 * im.height()); + + mapnik::svg::vertex_stl_adapter stl_storage(marker.get_data()->source()); + mapnik::svg::svg_path_adapter svg_path(stl_storage); + mapnik::svg::svg_renderer_agg, + renderer_solid, + agg::pixfmt_rgba32_pre > svg_renderer_this(svg_path, + marker.get_data()->attributes()); + + svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox); + + boost::algorithm::ireplace_last(svg_name_,".svg",".png"); + demultiply_alpha(im); + mapnik::save_to_file(im,svg_name_,"png"); + if (auto_open_) + { + std::ostringstream s; +#ifdef DARWIN + s << "open " << svg_name_; +#else + s << "xdg-open " << svg_name_; +#endif + int ret = system(s.str().c_str()); + if (ret != 0) + return_value_ = ret; + } + std::clog << "rendered to: " << svg_name_ << "\n"; + + } + + private: + std::string & svg_name_; + int & return_value_; + bool verbose_; + bool auto_open_; +}; int main (int argc,char** argv) { @@ -128,74 +213,9 @@ int main (int argc,char** argv) std::clog << "found: " << svg_name << "\n"; } - boost::optional marker_ptr = - mapnik::marker_cache::instance().find(svg_name, false); - if (!marker_ptr) - { - std::clog << "svg2png error: could not open: '" << svg_name << "'\n"; - return_value = -1; - continue; - } - mapnik::marker marker = **marker_ptr; - if (!marker.is_vector()) - { - std::clog << "svg2png error: '" << svg_name << "' is not a valid vector!\n"; - return_value = -1; - continue; - } - - using pixfmt = agg::pixfmt_rgba32_pre; - using renderer_base = agg::renderer_base; - using renderer_solid = agg::renderer_scanline_aa_solid; - agg::rasterizer_scanline_aa<> ras_ptr; - agg::scanline_u8 sl; - - double opacity = 1; - int w = marker.width(); - int h = marker.height(); - if (verbose) - { - std::clog << "found width of '" << w << "' and height of '" << h << "'\n"; - } - // 10 pixel buffer to avoid edge clipping of 100% svg's - mapnik::image_32 im(w+0,h+0); - agg::rendering_buffer buf(im.raw_data(), im.width(), im.height(), im.width() * 4); - pixfmt pixf(buf); - renderer_base renb(pixf); - - mapnik::box2d const& bbox = (*marker.get_vector_data())->bounding_box(); - mapnik::coord c = bbox.center(); - // center the svg marker on '0,0' - agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); - // render the marker at the center of the marker box - mtx.translate(0.5 * im.width(), 0.5 * im.height()); - - mapnik::svg::vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); - mapnik::svg::svg_path_adapter svg_path(stl_storage); - mapnik::svg::svg_renderer_agg, - renderer_solid, - agg::pixfmt_rgba32_pre > svg_renderer_this(svg_path, - (*marker.get_vector_data())->attributes()); - - svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox); - - boost::algorithm::ireplace_last(svg_name,".svg",".png"); - im.demultiply(); - mapnik::save_to_file(im.data(),svg_name,"png"); - if (auto_open) - { - std::ostringstream s; -#ifdef DARWIN - s << "open " << svg_name; -#else - s << "xdg-open " << svg_name; -#endif - int ret = system(s.str().c_str()); - if (ret != 0) - return_value = ret; - } - std::clog << "rendered to: " << svg_name << "\n"; + mapnik::marker const& marker = mapnik::marker_cache::instance().find(svg_name, false); + main_marker_visitor visitor(svg_name, return_value, verbose, auto_open); + mapnik::util::apply_visitor(visitor, marker); } } catch (...)