Merge branch 'master' into harfbuzz

Conflicts:
	src/symbolizer_helpers.cpp
This commit is contained in:
Hermann Kraus 2012-08-05 16:29:09 +02:00
commit e380a20b6c
13 changed files with 172 additions and 110 deletions

View file

@ -59,6 +59,35 @@ Not yet released
- Added support for justify-alignment=auto. This is the new default. (#1125)
## Mapnik 2.0.2
Released Aug 3, 2012
(Packaged from adb2ec741)
- Fixed handling of empty WKB geometries (#1334)
- Fixed naming of `stroke-dashoffset` in save_map (cc3cd5f63f28)
- Fixed support for boost 1.50 (8dea5a5fe239233)
- Fixed TextSymbolizer placement in Cairo backend so it respects avoid-edges and minimum-padding across all renderers (#1242)
- Fixed ShieldSymbolizer placement so it respects avoid-edges and minimum-padding across all renderers (#1242)
- Rolled back change made in 2.0.1 to marker width/height meaning that Mapnik > 2.0.2 will stick to assuming width/heigh are radii for back compatibility with 2.0.0. The reverted change is seen below as "Fix Markers rendering so that ellipse height/width units are pixels (previously were unintentionally radii)". Issue tracking this is #1163
- XML: Fixed to avoid throwing if a `<Parameters>` element is encountered (which is supported in >= 2.1.x)
- Support for PostGIS 2.0 in the pgsql2sqlite command (e69c44e/47e5b3c)
- Fixed reference counting of Py_None when returning null attributes from Postgres during UTFGrid encoding, which could cause a Fatal Python error: deallocating None (#1221)
- Fixed possible breakage registering plugins via python if a custom PREFIX or DESTDIR was used (e.g. macports/homebrew) (#1171)
- Fixed memory leak in the case of proj >= 4.8 and a projection initialization error (#1173)
## Mapnik 2.0.1
Released April 10, 2012

View file

@ -1058,17 +1058,17 @@ namespace agg
long_type sbda = sb * da;
long_type sada = sa * da;
if ( sr > 0) p[Order::R] = (value_type)(((srda + drsa <= sada) ?
sr * d1a + dr * s1a :
sa * (srda + drsa - sada) / sr + sr * d1a + dr * s1a + base_mask) >> base_shift);
p[Order::R] = (value_type)(((srda + drsa <= sada) ?
sr * d1a + dr * s1a :
(sr > 0 ? sa * (srda + drsa - sada) / sr + sr * d1a + dr * s1a + base_mask : 0)) >> base_shift);
if ( sg > 0 ) p[Order::G] = (value_type)(((sgda + dgsa <= sada) ?
p[Order::G] = (value_type)(((sgda + dgsa <= sada) ?
sg * d1a + dg * s1a :
sa * (sgda + dgsa - sada) / sg + sg * d1a + dg * s1a + base_mask) >> base_shift);
(sg > 0 ? sa * (sgda + dgsa - sada) / sg + sg * d1a + dg * s1a + base_mask : 0)) >> base_shift);
if ( sb > 0) p[Order::B] = (value_type)(((sbda + dbsa <= sada) ?
p[Order::B] = (value_type)(((sbda + dbsa <= sada) ?
sb * d1a + db * s1a :
sa * (sbda + dbsa - sada) / sb + sb * d1a + db * s1a + base_mask) >> base_shift);
(sb > 0 ? sa * (sbda + dbsa - sada) / sb + sb * d1a + db * s1a + base_mask : 0)) >> base_shift);
p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift));
}
@ -1468,31 +1468,38 @@ namespace agg
// source rgb
unsigned sr, unsigned sg, unsigned sb,
// source alpha and opacity
unsigned sa, unsigned cover) {
if (cover < 255) {
unsigned sa, unsigned cover)
{
if(cover < 255)
{
sr = (sr * cover + 255) >> 8;
sg = (sg * cover + 255) >> 8;
sb = (sb * cover + 255) >> 8;
sa = (sa * cover + 255) >> 8;
}
p[Order::R] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::G] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::B] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
// http://en.wikipedia.org/wiki/File:HSV-RGB-comparison.svg
if (p[Order::A] < 64) {
p[Order::G] = ((p[Order::A] - 64) * 4);
p[Order::B] = 255;
}
if (p[Order::A] >= 64 && p[Order::A] < 128) {
p[Order::G] = 255;
p[Order::B] = 255 - ((p[Order::A] - 64) * 4);
}
if (p[Order::A] >= 128 && p[Order::A] < 192) {
p[Order::R] = ((p[Order::A] - 128) * 4);
p[Order::G] = 255;
}
if (p[Order::A] >= 192) {
p[Order::R] = 255;
p[Order::G] = 255 - ((p[Order::A] - 192) * 4);
if (sa > 0)
{
p[Order::R] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::G] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::B] = (value_type)(((0 + base_mask) >> base_shift));
p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift));
// http://en.wikipedia.org/wiki/File:HSV-RGB-comparison.svg
if (p[Order::A] < 64) {
p[Order::G] = ((p[Order::A] - 64) * 4);
p[Order::B] = 255;
}
if (p[Order::A] >= 64 && p[Order::A] < 128) {
p[Order::G] = 255;
p[Order::B] = 255 - ((p[Order::A] - 64) * 4);
}
if (p[Order::A] >= 128 && p[Order::A] < 192) {
p[Order::R] = ((p[Order::A] - 128) * 4);
p[Order::G] = 255;
}
if (p[Order::A] >= 192) {
p[Order::R] = 255;
p[Order::G] = 255 - ((p[Order::A] - 192) * 4);
}
}
}
};

View file

@ -104,7 +104,7 @@ struct vector_markers_rasterizer_dispatch
if (sym_.get_allow_overlap() ||
detector_.has_placement(transformed_bbox))
{
svg_renderer_.render(ras_, sl_, renb_, matrix, 1, bbox_);
svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
if (!sym_.get_ignore_placement())
detector_.insert(transformed_bbox);
@ -122,7 +122,7 @@ struct vector_markers_rasterizer_dispatch
agg::trans_affine matrix = marker_trans_;
matrix.rotate(angle);
matrix.translate(x, y);
svg_renderer_.render(ras_, sl_, renb_, matrix, 1, bbox_);
svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
}
}
}
@ -248,10 +248,8 @@ struct raster_markers_rasterizer_dispatch
if (sym_.get_allow_overlap() ||
detector_.has_placement(transformed_bbox))
{
float opacity = sym_.get_opacity() ? *sym_.get_opacity() : 1;
render_raster_marker(ras_, renb_, sl_, src_,
matrix, opacity);
matrix, sym_.get_opacity());
if (!sym_.get_ignore_placement())
detector_.insert(transformed_bbox);
}
@ -268,9 +266,8 @@ struct raster_markers_rasterizer_dispatch
agg::trans_affine matrix = marker_trans_;
matrix.rotate(angle);
matrix.translate(x,y);
float opacity = sym_.get_opacity() ? *sym_.get_opacity() : 1;
render_raster_marker(ras_, renb_, sl_, src_,
matrix, opacity);
matrix, sym_.get_opacity());
}
}
}
@ -327,9 +324,8 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const&
{
boost::optional<stroke> const& strk = sym.get_stroke();
boost::optional<color> const& fill = sym.get_fill();
boost::optional<float> const& opacity = sym.get_opacity();
boost::optional<float> const& fill_opacity = sym.get_fill_opacity();
if (strk || fill || opacity || fill_opacity)
if (strk || fill || fill_opacity)
{
bool success = false;
for(unsigned i = 0; i < src.size(); ++i)
@ -349,13 +345,6 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const&
s_color.green()/255.0,
s_color.blue()/255.0,
s_color.alpha()/255.0);
}
if (opacity)
{
attr.stroke_opacity = *opacity;
}
else if (strk)
{
attr.stroke_opacity = strk->get_opacity();
}
}
@ -369,11 +358,7 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const&
f_color.blue()/255.0,
f_color.alpha()/255.0);
}
if (opacity)
{
attr.fill_opacity = *opacity;
}
else if (fill_opacity)
if (fill_opacity)
{
attr.fill_opacity = *fill_opacity;
}

View file

@ -66,8 +66,6 @@ public:
double get_spacing() const;
void set_max_error(double max_error);
double get_max_error() const;
void set_opacity(float opacity);
boost::optional<float> get_opacity() const;
void set_fill(color const& fill);
boost::optional<color> get_fill() const;
void set_fill_opacity(float opacity);

View file

@ -27,6 +27,7 @@
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/feature_factory.hpp>
#include <mapnik/debug.hpp>
#include "osm_featureset.hpp"
@ -61,7 +62,7 @@ feature_ptr osm_featureset<filterT>::next()
if (!cur_item) return feature_ptr();
if (dataset_->current_item_is_node())
{
feature = feature_factory::create(ctx_,feature_id_);
feature = feature_factory::create(ctx_, feature_id_);
++feature_id_;
double lat = static_cast<osm_node*>(cur_item)->lat;
double lon = static_cast<osm_node*>(cur_item)->lon;
@ -75,49 +76,52 @@ feature_ptr osm_featureset<filterT>::next()
while (cur_item)
{
bounds b = static_cast<osm_way*>(cur_item)->get_bounds();
if (filter_.pass(box2d<double>(b.w, b.s, b.e, b.n))) break;
if (filter_.pass(box2d<double>(b.w, b.s, b.e, b.n))
&&
static_cast<osm_way*>(cur_item)->nodes.size()) break;
cur_item = dataset_->next_item();
}
if (!cur_item) return feature_ptr();
if (static_cast<osm_way*>(cur_item)->nodes.size())
feature = feature_factory::create(ctx_, feature_id_);
++feature_id_;
geometry_type* geom;
if (static_cast<osm_way*>(cur_item)->is_polygon())
{
feature = feature_factory::create(ctx_,feature_id_);
++feature_id_;
geometry_type* geom;
if (static_cast<osm_way*>(cur_item)->is_polygon())
{
geom = new geometry_type(mapnik::Polygon);
}
else
{
geom = new geometry_type(mapnik::LineString);
}
geom->move_to(static_cast<osm_way*>(cur_item)->nodes[0]->lon,
static_cast<osm_way*>(cur_item)->nodes[0]->lat);
for (unsigned int count = 1;
count < static_cast<osm_way*>(cur_item)->nodes.size();
count++)
{
geom->line_to(static_cast<osm_way*>(cur_item)->nodes[count]->lon,
static_cast<osm_way*>(cur_item)->nodes[count]->lat);
}
feature->add_geometry(geom);
geom = new geometry_type(mapnik::Polygon);
}
else
{
geom = new geometry_type(mapnik::LineString);
}
geom->move_to(static_cast<osm_way*>(cur_item)->nodes[0]->lon,
static_cast<osm_way*>(cur_item)->nodes[0]->lat);
for (unsigned int count = 1;
count < static_cast<osm_way*>(cur_item)->nodes.size();
count++)
{
geom->line_to(static_cast<osm_way*>(cur_item)->nodes[count]->lon,
static_cast<osm_way*>(cur_item)->nodes[count]->lat);
}
feature->add_geometry(geom);
} else
{
MAPNIK_LOG_FATAL(osm_featureset) << "Current item is neither node nor way.\n";
}
std::set<std::string>::const_iterator itr = attribute_names_.begin();
std::set<std::string>::const_iterator end = attribute_names_.end();
std::map<std::string,std::string>::iterator end_keyvals = cur_item->keyvals.end();
for (; itr != end; itr++)
{
std::map<std::string,std::string>::iterator i = cur_item->keyvals.find(*itr);
if (i != end_keyvals) {
feature->put_new(i->first,tr_->transcode(i->second.c_str()));
} else {
if (i != end_keyvals)
{
feature->put_new(i->first, tr_->transcode(i->second.c_str()));
} else
{
feature->put_new(*itr, "");
}
}

View file

@ -1047,7 +1047,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
sym.set_filename(expr);
}
// overall opacity - impacts both fill and stroke, like svg
// overall opacity to be applied to all paths
optional<float> opacity = node.get_opt_attr<float>("opacity");
if (opacity) sym.set_opacity(*opacity);

View file

@ -70,7 +70,6 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
max_error_(rhs.max_error_),
fill_(rhs.fill_),
fill_opacity_(rhs.fill_opacity_),
opacity_(rhs.opacity_),
stroke_(rhs.stroke_),
marker_p_(rhs.marker_p_) {}
@ -114,16 +113,6 @@ double markers_symbolizer::get_max_error() const
return max_error_;
}
void markers_symbolizer::set_opacity(float opacity)
{
opacity_ = opacity;
}
boost::optional<float> markers_symbolizer::get_opacity() const
{
return opacity_;
}
void markers_symbolizer::set_fill(color const& fill)
{
fill_ = fill;

View file

@ -247,7 +247,6 @@ void text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_points()
/*****************************************************************************/
template <typename FaceManagerT, typename DetectorT>
shield_symbolizer_helper<FaceManagerT, DetectorT>::shield_symbolizer_helper(const shield_symbolizer &sym, const Feature &feature, const proj_transform &prj_trans, unsigned width, unsigned height, double scale_factor, const CoordTransform &t, FaceManagerT &font_manager, DetectorT &detector, const box2d<double> &query_extent)
: text_symbolizer_helper<FaceManagerT, DetectorT>(

View file

@ -62,8 +62,10 @@ bool placement_finder_ng::next_position()
if (info_->properties.orientation)
{
// https://github.com/mapnik/mapnik/issues/1352
mapnik::evaluate<Feature, value_type> evaluator(feature_);
angle_ = boost::apply_visitor(
evaluate<Feature, value_type>(feature_),
evaluator,
*(info_->properties.orientation)).to_double() * M_PI / 180.0;
} else {
angle_ = 0.0;

View file

@ -11,6 +11,49 @@ def setup():
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def validate_pixels_are_demultiplied(image):
bad_pixels = []
for x in range(0,image.width(),2):
for y in range(0,image.height(),2):
pixel = image.get_pixel(x,y)
r = pixel & 0xff
g = (pixel >> 8) & 0xff
b = (pixel >> 16) & 0xff
a = (pixel >> 24) & 0xff
is_valid = (r >=0 and r < 256) and \
(g >=0 and g < 256) and \
(b >=0 and b < 256) and \
(a >=0 and a < 256)
if not is_valid:
bad_pixels.append("rgba(%s,%s,%s,%s) at %s,%s" % (r,g,b,a,x,y))
num_bad = len(bad_pixels)
return (num_bad == 0,num_bad)
def validate_pixels_are_premultiplied(image):
bad_pixels = []
for x in range(0,image.width(),2):
for y in range(0,image.height(),2):
pixel = image.get_pixel(x,y)
red = pixel & 0xff
green = (pixel >> 8) & 0xff
blue = (pixel >> 16) & 0xff
alpha = (pixel >> 24) & 0xff
a2 = alpha
if a2 == 0:
a2 = 1
else:
a2 = a2*256
is_valid = (red >=0 and red/a2 < 256) and \
(green >=0 and red/a2 < 256) and \
(blue >=0 and red/a2 < 256) and \
(alpha >=0 and alpha < 256)
if not is_valid:
import pdb;pdb.set_trace()
bad_pixels.append("rgba(%s,%s,%s,%s) at %s,%s" % (red,green,blue,alpha,x,y))
num_bad = len(bad_pixels)
return (num_bad == 0,bad_pixels)
def test_compare_images():
b = mapnik.Image.open('./images/support/b.png')
b.premultiply()
@ -20,7 +63,13 @@ def test_compare_images():
a.composite(b,getattr(mapnik.CompositeOp,name))
actual = '/tmp/mapnik-comp-op-test-' + name + '.png'
expected = 'images/composited/' + name + '.png'
valid = validate_pixels_are_premultiplied(a)
if not valid[0]:
print '%s not validly pre-:\n\t%s pixels (%s)' % (name,len(valid[1]),valid[1][0])
a.demultiply()
valid = validate_pixels_are_demultiplied(a)
if not valid[0]:
print '%s not validly de-:\n\t%s pixels (%s)' % (name,len(valid[1]),valid[1][0])
a.save(actual)
expected_im = mapnik.Image.open(expected)
# compare them

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -21,18 +21,18 @@ def test_marker_ellipse_render1():
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
#def test_marker_ellipse_render2():
# # currently crashes https://github.com/mapnik/mapnik/issues/1365
# m = mapnik.Map(256,256)
# mapnik.load_map(m,'../data/good_maps/marker_ellipse_transform2.xml')
# m.zoom_all()
# im = mapnik.Image(m.width,m.height)
# mapnik.render(m,im)
# actual = '/tmp/mapnik-marker-ellipse-render2.png'
# expected = 'images/support/mapnik-marker-ellipse-render2.png'
# im.save(actual)
# expected_im = mapnik.Image.open(expected)
# eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
def test_marker_ellipse_render2():
# currently crashes https://github.com/mapnik/mapnik/issues/1365
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/marker_ellipse_transform2.xml')
m.zoom_all()
im = mapnik.Image(m.width,m.height)
mapnik.render(m,im)
actual = '/tmp/mapnik-marker-ellipse-render2.png'
expected = 'images/support/mapnik-marker-ellipse-render2.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
if __name__ == "__main__":
setup()

View file

@ -135,7 +135,7 @@ def test_pointsymbolizer_init():
def test_markersymbolizer_init():
p = mapnik.MarkersSymbolizer()
eq_(p.allow_overlap, False)
eq_(p.opacity,None)
eq_(p.opacity,1.0)
eq_(p.fill_opacity,None)
eq_(p.filename,'shape://ellipse')
eq_(p.placement,mapnik.marker_placement.POINT_PLACEMENT)