Vector patterns with Cairo
This commit is contained in:
parent
940f0dc39d
commit
2344fe3ac2
2 changed files with 121 additions and 49 deletions
|
@ -121,6 +121,30 @@ private:
|
||||||
cairo_face_cache cache_;
|
cairo_face_cache cache_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cairo_closer
|
||||||
|
{
|
||||||
|
void operator() (cairo_t * obj)
|
||||||
|
{
|
||||||
|
if (obj) cairo_destroy(obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cairo_surface_closer
|
||||||
|
{
|
||||||
|
void operator() (cairo_surface_t * surface)
|
||||||
|
{
|
||||||
|
if (surface) cairo_surface_destroy(surface);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using cairo_ptr = std::shared_ptr<cairo_t>;
|
||||||
|
using cairo_surface_ptr = std::shared_ptr<cairo_surface_t>;
|
||||||
|
|
||||||
|
inline cairo_ptr create_context(cairo_surface_ptr const& surface)
|
||||||
|
{
|
||||||
|
return cairo_ptr(cairo_create(&*surface),cairo_closer());
|
||||||
|
}
|
||||||
|
|
||||||
class cairo_pattern : private util::noncopyable
|
class cairo_pattern : private util::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -131,9 +155,15 @@ public:
|
||||||
const unsigned int *in_end = in_ptr + pixels;
|
const unsigned int *in_end = in_ptr + pixels;
|
||||||
unsigned int *out_ptr;
|
unsigned int *out_ptr;
|
||||||
|
|
||||||
surface_ = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, static_cast<int>(data.width()), static_cast<int>(data.height()));
|
surface_ = cairo_surface_ptr(
|
||||||
|
cairo_image_surface_create(
|
||||||
|
CAIRO_FORMAT_ARGB32,
|
||||||
|
static_cast<int>(data.width()),
|
||||||
|
static_cast<int>(data.height())),
|
||||||
|
cairo_surface_closer());
|
||||||
|
|
||||||
out_ptr = reinterpret_cast<unsigned int *>(cairo_image_surface_get_data(surface_));
|
out_ptr = reinterpret_cast<unsigned int *>(
|
||||||
|
cairo_image_surface_get_data(surface_.get()));
|
||||||
|
|
||||||
while (in_ptr < in_end)
|
while (in_ptr < in_end)
|
||||||
{
|
{
|
||||||
|
@ -150,13 +180,18 @@ public:
|
||||||
*out_ptr++ = (a << 24) | (r << 16) | (g << 8) | b;
|
*out_ptr++ = (a << 24) | (r << 16) | (g << 8) | b;
|
||||||
}
|
}
|
||||||
// mark the surface as dirty as we've modified it behind cairo's back
|
// mark the surface as dirty as we've modified it behind cairo's back
|
||||||
cairo_surface_mark_dirty(surface_);
|
cairo_surface_mark_dirty(surface_.get());
|
||||||
pattern_ = cairo_pattern_create_for_surface(surface_);
|
pattern_ = cairo_pattern_create_for_surface(surface_.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_pattern(cairo_surface_ptr const& surface) :
|
||||||
|
surface_(surface),
|
||||||
|
pattern_(cairo_pattern_create_for_surface(surface_.get()))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
~cairo_pattern()
|
~cairo_pattern()
|
||||||
{
|
{
|
||||||
if (surface_) cairo_surface_destroy(surface_);
|
|
||||||
if (pattern_) cairo_pattern_destroy(pattern_);
|
if (pattern_) cairo_pattern_destroy(pattern_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +225,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cairo_surface_t * surface_;
|
cairo_surface_ptr surface_;
|
||||||
cairo_pattern_t * pattern_;
|
cairo_pattern_t * pattern_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,30 +290,6 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cairo_closer
|
|
||||||
{
|
|
||||||
void operator() (cairo_t * obj)
|
|
||||||
{
|
|
||||||
if (obj) cairo_destroy(obj);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cairo_surface_closer
|
|
||||||
{
|
|
||||||
void operator() (cairo_surface_t * surface)
|
|
||||||
{
|
|
||||||
if (surface) cairo_surface_destroy(surface);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using cairo_ptr = std::shared_ptr<cairo_t>;
|
|
||||||
using cairo_surface_ptr = std::shared_ptr<cairo_surface_t>;
|
|
||||||
|
|
||||||
inline cairo_ptr create_context(cairo_surface_ptr const& surface)
|
|
||||||
{
|
|
||||||
return cairo_ptr(cairo_create(&*surface),cairo_closer());
|
|
||||||
}
|
|
||||||
|
|
||||||
class cairo_context : private util::noncopyable
|
class cairo_context : private util::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -27,40 +27,92 @@
|
||||||
#include <mapnik/vertex_processor.hpp>
|
#include <mapnik/vertex_processor.hpp>
|
||||||
#include <mapnik/vertex_converters.hpp>
|
#include <mapnik/vertex_converters.hpp>
|
||||||
#include <mapnik/renderer_common/pattern_alignment.hpp>
|
#include <mapnik/renderer_common/pattern_alignment.hpp>
|
||||||
#include <mapnik/renderer_common/render_pattern.hpp>
|
|
||||||
#include <mapnik/renderer_common/apply_vertex_converter.hpp>
|
#include <mapnik/renderer_common/apply_vertex_converter.hpp>
|
||||||
#include <mapnik/renderer_common/clipping_extent.hpp>
|
#include <mapnik/renderer_common/clipping_extent.hpp>
|
||||||
#include <mapnik/agg_rasterizer.hpp>
|
#include <mapnik/cairo/cairo_render_vector.hpp>
|
||||||
#include <mapnik/marker.hpp>
|
#include <mapnik/marker.hpp>
|
||||||
|
|
||||||
namespace mapnik {
|
namespace mapnik {
|
||||||
|
|
||||||
struct cairo_renderer_process_visitor_p
|
struct cairo_renderer_process_visitor_p
|
||||||
{
|
{
|
||||||
cairo_renderer_process_visitor_p(agg::trans_affine & image_tr)
|
cairo_renderer_process_visitor_p(agg::trans_affine const& image_tr,
|
||||||
: image_tr_(image_tr)
|
double opacity)
|
||||||
|
: image_tr_(image_tr),
|
||||||
|
opacity_(opacity)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
image_rgba8 operator() (marker_null const&)
|
cairo_surface_ptr operator()(marker_svg const & marker) const
|
||||||
{
|
{
|
||||||
return image_rgba8();
|
box2d<double> bbox(marker.bounding_box());
|
||||||
|
agg::trans_affine tr(transform(bbox));
|
||||||
|
|
||||||
|
double width = std::max(1.0, std::round(bbox.width()));
|
||||||
|
double height = std::max(1.0, std::round(bbox.height()));
|
||||||
|
cairo_rectangle_t extent { 0, 0, width, height };
|
||||||
|
cairo_surface_ptr surface(
|
||||||
|
cairo_recording_surface_create(
|
||||||
|
CAIRO_CONTENT_COLOR_ALPHA, &extent),
|
||||||
|
cairo_surface_closer());
|
||||||
|
|
||||||
|
cairo_ptr cairo = create_context(surface);
|
||||||
|
cairo_context context(cairo);
|
||||||
|
|
||||||
|
svg_storage_type & svg = *marker.get_data();
|
||||||
|
svg_attribute_type const& svg_attributes = svg.attributes();
|
||||||
|
svg::vertex_stl_adapter<svg::svg_path_storage> stl_storage(
|
||||||
|
svg.source());
|
||||||
|
svg::svg_path_adapter svg_path(stl_storage);
|
||||||
|
|
||||||
|
render_vector_marker(context, svg_path, svg_attributes,
|
||||||
|
bbox, tr, opacity_);
|
||||||
|
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
image_rgba8 operator() (marker_svg const& marker)
|
cairo_surface_ptr operator()(marker_rgba8 const& marker) const
|
||||||
{
|
{
|
||||||
mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr_;
|
box2d<double> bbox(marker.bounding_box());
|
||||||
mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
|
agg::trans_affine tr(transform(bbox));
|
||||||
render_pattern<image_rgba8>(marker, image_tr_, 1.0, image);
|
|
||||||
return image;
|
cairo_rectangle_t extent { 0, 0, bbox.width(), bbox.height() };
|
||||||
|
cairo_surface_ptr surface(
|
||||||
|
cairo_recording_surface_create(
|
||||||
|
CAIRO_CONTENT_COLOR_ALPHA, &extent),
|
||||||
|
cairo_surface_closer());
|
||||||
|
|
||||||
|
cairo_ptr cairo = create_context(surface);
|
||||||
|
cairo_context context(cairo);
|
||||||
|
|
||||||
|
context.add_image(tr, marker.get_data(), opacity_);
|
||||||
|
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
image_rgba8 operator() (marker_rgba8 const& marker)
|
cairo_surface_ptr operator() (marker_null const&) const
|
||||||
{
|
{
|
||||||
return marker.get_data();
|
cairo_surface_ptr surface(
|
||||||
|
cairo_recording_surface_create(
|
||||||
|
CAIRO_CONTENT_COLOR_ALPHA, nullptr),
|
||||||
|
cairo_surface_closer());
|
||||||
|
cairo_ptr cairo = create_context(surface);
|
||||||
|
cairo_context context(cairo);
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
agg::trans_affine & image_tr_;
|
agg::trans_affine transform(box2d<double> & bbox) const
|
||||||
|
{
|
||||||
|
bbox *= image_tr_;
|
||||||
|
coord<double, 2> c = bbox.center();
|
||||||
|
agg::trans_affine mtx = agg::trans_affine_translation(
|
||||||
|
0.5 * bbox.width() - c.x,
|
||||||
|
0.5 * bbox.height() - c.y);
|
||||||
|
return image_tr_ * mtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
agg::trans_affine const& image_tr_;
|
||||||
|
const double opacity_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cairo_pattern_base
|
struct cairo_pattern_base
|
||||||
|
@ -121,10 +173,19 @@ struct cairo_polygon_pattern : cairo_pattern_base
|
||||||
cairo_save_restore guard(context);
|
cairo_save_restore guard(context);
|
||||||
context.set_operator(comp_op);
|
context.set_operator(comp_op);
|
||||||
|
|
||||||
image_rgba8 pattern_img(util::apply_visitor(cairo_renderer_process_visitor_p(image_tr), marker_));
|
cairo_renderer_process_visitor_p visitor(image_tr, opacity);
|
||||||
coord<double, 2> offset(pattern_offset(sym_, feature_, prj_trans_, common_,
|
cairo_surface_ptr surface(util::apply_visitor(visitor, this->marker_));
|
||||||
pattern_img.width(), pattern_img.height()));
|
|
||||||
cairo_pattern pattern(pattern_img, opacity);
|
coord<double, 2> offset(0, 0);
|
||||||
|
|
||||||
|
cairo_rectangle_t pattern_surface_extent;
|
||||||
|
if (cairo_recording_surface_get_extents(surface.get(), &pattern_surface_extent))
|
||||||
|
{
|
||||||
|
offset = pattern_offset(sym_, feature_, prj_trans_, common_,
|
||||||
|
pattern_surface_extent.width, pattern_surface_extent.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_pattern pattern(surface);
|
||||||
pattern.set_extend(CAIRO_EXTEND_REPEAT);
|
pattern.set_extend(CAIRO_EXTEND_REPEAT);
|
||||||
pattern.set_origin(-offset.x, -offset.y);
|
pattern.set_origin(-offset.x, -offset.y);
|
||||||
context.set_pattern(pattern);
|
context.set_pattern(pattern);
|
||||||
|
|
Loading…
Reference in a new issue