Merge commit '0b9ebe21dd593b9b87c6388291b79a5c5a4af4e4' into harfbuzz

Conflicts:
	tests/visual_tests/test.py
This commit is contained in:
Hermann Kraus 2013-03-16 12:39:47 +01:00
commit a9973837ef
30 changed files with 170 additions and 26 deletions

View file

@ -176,6 +176,7 @@ boost::shared_ptr<image_32> from_cairo(PycairoSurface* surface)
void export_image() void export_image()
{ {
using namespace boost::python; using namespace boost::python;
// NOTE: must match list in include/mapnik/image_compositing.hpp
enum_<mapnik::composite_mode_e>("CompositeOp") enum_<mapnik::composite_mode_e>("CompositeOp")
.value("clear", mapnik::clear) .value("clear", mapnik::clear)
.value("src", mapnik::src) .value("src", mapnik::src)
@ -204,7 +205,12 @@ void export_image()
.value("exclusion", mapnik::exclusion) .value("exclusion", mapnik::exclusion)
.value("contrast", mapnik::contrast) .value("contrast", mapnik::contrast)
.value("invert", mapnik::invert) .value("invert", mapnik::invert)
.value("invert_rgb", mapnik::invert_rgb) .value("grain_merge", mapnik::grain_merge)
.value("grain_extract", mapnik::grain_extract)
.value("hue", mapnik::hue)
.value("saturation", mapnik::saturation)
.value("color", mapnik::_color)
.value("value", mapnik::_value)
; ;
class_<image_32,boost::shared_ptr<image_32> >("Image","This class represents a 32 bit RGBA image.",init<int,int>()) class_<image_32,boost::shared_ptr<image_32> >("Image","This class represents a 32 bit RGBA image.",init<int,int>())

View file

@ -28,6 +28,18 @@
#include <mapnik/raster_colorizer.hpp> #include <mapnik/raster_colorizer.hpp>
#include <mapnik/image_scaling.hpp> #include <mapnik/image_scaling.hpp>
namespace {
// https://github.com/mapnik/mapnik/issues/1367
PyObject* get_premultiplied_impl(mapnik::raster_symbolizer & sym)
{
boost::optional<bool> premultiplied = sym.premultiplied();
if (premultiplied)
return ::PyBool_FromLong(*premultiplied);
Py_RETURN_NONE;
}
}
using mapnik::raster_symbolizer; using mapnik::raster_symbolizer;
void export_raster_symbolizer() void export_raster_symbolizer()
@ -119,5 +131,17 @@ void export_raster_symbolizer()
">>> r = RasterSymbolizer()\n" ">>> r = RasterSymbolizer()\n"
">>> r.mesh_size = 32\n" ">>> r.mesh_size = 32\n"
) )
.add_property("premultiplied",
&get_premultiplied_impl,
&raster_symbolizer::set_premultiplied,
"Get/Set premultiplied status of the source image.\n"
"Can be used to override what the source data reports (when in error)\n"
"\n"
"Usage:\n"
"\n"
">>> from mapnik import RasterSymbolizer\n"
">>> r = RasterSymbolizer()\n"
">>> r.premultiplied = False\n"
)
; ;
} }

View file

@ -60,9 +60,16 @@ struct default_color_converter_impl< rgb_t, hsv_t >
bits32f temp_blue = channel_convert<bits32f>( get_color( src, blue_t() )); bits32f temp_blue = channel_convert<bits32f>( get_color( src, blue_t() ));
bits32f hue, saturation, value; bits32f hue, saturation, value;
bits32f min_color, max_color;
bits32f min_color = std::min(temp_red,std::min(temp_green, temp_blue)); if( temp_red < temp_green ) {
bits32f max_color = std::max(temp_red,std::max(temp_green, temp_blue)); min_color = std::min( temp_blue, temp_red );
max_color = std::max( temp_blue, temp_green );
}
else {
min_color = std::min( temp_blue, temp_green );
max_color = std::max( temp_blue, temp_red );
}
value = max_color; value = max_color;
@ -85,7 +92,7 @@ struct default_color_converter_impl< rgb_t, hsv_t >
} }
else else
{ {
if( std::abs( boost::numeric_cast<int>(temp_red - max_color) ) < 0.0001f ) if( temp_red == max_color )
{ {
hue = ( temp_green - temp_blue ) hue = ( temp_green - temp_blue )
/ diff; / diff;
@ -149,18 +156,23 @@ struct default_color_converter_impl<hsv_t,rgb_t>
frac = h - i; frac = h - i;
// p = value * (1 - saturation)
p = get_color( src, value_t() ) p = get_color( src, value_t() )
* ( 1.f - get_color( src, saturation_t() )); * ( 1.f - get_color( src, saturation_t() ));
// q = value * (1 - saturation * hue_frac)
// it drops with increasing distance from floor(hue)
q = get_color( src, value_t() ) q = get_color( src, value_t() )
* ( 1.f - ( get_color( src, saturation_t() ) * frac )); * ( 1.f - ( get_color( src, saturation_t() ) * frac ));
// t = value * (1 - (saturation * (1 - hue_frac))
// it grows with increasing distance from floor(hue)
t = get_color( src, value_t() ) t = get_color( src, value_t() )
* ( 1.f - ( get_color( src, saturation_t() ) * ( 1.f - frac ))); * ( 1.f - ( get_color( src, saturation_t() ) * ( 1.f - frac )));
switch( i ) switch( i % 6 )
{ {
case 0: case 0: // red to yellow
{ {
red = get_color( src, value_t() ); red = get_color( src, value_t() );
green = t; green = t;
@ -169,7 +181,7 @@ struct default_color_converter_impl<hsv_t,rgb_t>
break; break;
} }
case 1: case 1: // yellow to green
{ {
red = q; red = q;
green = get_color( src, value_t() ); green = get_color( src, value_t() );
@ -178,7 +190,7 @@ struct default_color_converter_impl<hsv_t,rgb_t>
break; break;
} }
case 2: case 2: // green to cyan
{ {
red = p; red = p;
green = get_color( src, value_t() ); green = get_color( src, value_t() );
@ -187,7 +199,7 @@ struct default_color_converter_impl<hsv_t,rgb_t>
break; break;
} }
case 3: case 3: // cyan to blue
{ {
red = p; red = p;
green = q; green = q;
@ -196,7 +208,7 @@ struct default_color_converter_impl<hsv_t,rgb_t>
break; break;
} }
case 4: case 4: // blue to magenta
{ {
red = t; red = t;
green = p; green = p;
@ -205,7 +217,7 @@ struct default_color_converter_impl<hsv_t,rgb_t>
break; break;
} }
case 5: case 5: // magenta to red
{ {
red = get_color( src, value_t() ); red = get_color( src, value_t() );
green = p; green = p;

View file

@ -30,6 +30,7 @@
// boost // boost
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
namespace mapnik namespace mapnik
{ {
@ -52,6 +53,8 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base
double calculate_filter_factor() const; double calculate_filter_factor() const;
unsigned get_mesh_size() const; unsigned get_mesh_size() const;
void set_mesh_size(unsigned mesh_size); void set_mesh_size(unsigned mesh_size);
boost::optional<bool> premultiplied() const;
void set_premultiplied(bool premultiplied);
private: private:
std::string mode_; std::string mode_;
@ -60,6 +63,7 @@ private:
raster_colorizer_ptr colorizer_; raster_colorizer_ptr colorizer_;
double filter_factor_; double filter_factor_;
unsigned mesh_size_; unsigned mesh_size_;
boost::optional<bool> premultiplied_;
}; };
} }

View file

@ -489,7 +489,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q)
image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); image.width(), image.height(), GDT_Byte, 4, 4 * image.width());
} }
feature->set_raster(mapnik::raster_ptr(new mapnik::raster(intersect, image))); feature->set_raster(boost::make_shared<mapnik::raster>(intersect, image));
} }
return feature; return feature;
} }

View file

@ -98,9 +98,20 @@ void agg_renderer<T>::process(raster_symbolizer const& sym,
filter_radius); filter_radius);
} }
} }
// handle whether to premultiply the source
// data before compositing
// first, default to what the data reports
bool premultiply_source = !source->premultiplied_alpha_;
// the, allow the user to override
boost::optional<bool> is_premultiplied = sym.premultiplied();
if (is_premultiplied)
{
if (*is_premultiplied) premultiply_source = false;
else premultiply_source = true;
}
composite(current_buffer_->data(), target.data_, composite(current_buffer_->data(), target.data_,
sym.comp_op(), sym.get_opacity(), sym.comp_op(), sym.get_opacity(),
start_x, start_y, !source->premultiplied_alpha_); start_x, start_y, premultiply_source);
} }
} }
} }

View file

@ -345,6 +345,8 @@ else:
env['LIBMAPNIK_LIBS'] = copy(lib_env['LIBS']) env['LIBMAPNIK_LIBS'] = copy(lib_env['LIBS'])
env['LIBMAPNIK_CXXFLAGS'] = libmapnik_cxxflags env['LIBMAPNIK_CXXFLAGS'] = libmapnik_cxxflags
mapnik = None
if env['PLATFORM'] == 'Darwin': if env['PLATFORM'] == 'Darwin':
target_path = env['MAPNIK_LIB_BASE_DEST'] target_path = env['MAPNIK_LIB_BASE_DEST']
if 'uninstall' not in COMMAND_LINE_TARGETS: if 'uninstall' not in COMMAND_LINE_TARGETS:
@ -395,3 +397,5 @@ else:
env['create_uninstall_target'](env, target2) env['create_uninstall_target'](env, target2)
env['create_uninstall_target'](env, target1) env['create_uninstall_target'](env, target1)
env['create_uninstall_target'](env, target) env['create_uninstall_target'](env, target)
Depends(mapnik, env.subst('../deps/agg/libagg.a'))

View file

@ -1254,7 +1254,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym)
sym.get_opt_attr<boolean>("no-text"); sym.get_opt_attr<boolean>("no-text");
if (no_text) if (no_text)
{ {
MAPNIK_LOG_ERROR(raster_symbolizer) << "'no-text' is deprecated and will be removed in Mapnik 3.x, to create a ShieldSymbolizer without text just provide an element like: \"<ShieldSymbolizer ... />' '</>\""; MAPNIK_LOG_ERROR(shield_symbolizer) << "'no-text' is deprecated and will be removed in Mapnik 3.x, to create a ShieldSymbolizer without text just provide an element like: \"<ShieldSymbolizer ... />' '</>\"";
if (*no_text) if (*no_text)
shield_symbol.set_name(parse_expression("' '")); shield_symbol.set_name(parse_expression("' '"));
} }
@ -1491,6 +1491,9 @@ void map_parser::parse_raster_symbolizer(rule & rule, xml_node const & sym)
optional<unsigned> mesh_size = sym.get_opt_attr<unsigned>("mesh-size"); optional<unsigned> mesh_size = sym.get_opt_attr<unsigned>("mesh-size");
if (mesh_size) raster_sym.set_mesh_size(*mesh_size); if (mesh_size) raster_sym.set_mesh_size(*mesh_size);
// premultiplied status of image
optional<boolean> premultiplied = sym.get_opt_attr<boolean>("premultiplied");
if (premultiplied) raster_sym.set_premultiplied(*premultiplied);
xml_node::const_iterator cssIter = sym.begin(); xml_node::const_iterator cssIter = sym.begin();
xml_node::const_iterator endCss = sym.end(); xml_node::const_iterator endCss = sym.end();

View file

@ -55,7 +55,8 @@ raster_symbolizer::raster_symbolizer(raster_symbolizer const& rhs)
opacity_(rhs.opacity_), opacity_(rhs.opacity_),
colorizer_(rhs.colorizer_), colorizer_(rhs.colorizer_),
filter_factor_(rhs.filter_factor_), filter_factor_(rhs.filter_factor_),
mesh_size_(rhs.mesh_size_) {} mesh_size_(rhs.mesh_size_),
premultiplied_(rhs.premultiplied_) {}
std::string const& raster_symbolizer::get_mode() const std::string const& raster_symbolizer::get_mode() const
{ {
@ -177,6 +178,15 @@ void raster_symbolizer::set_mesh_size(unsigned mesh_size)
mesh_size_=mesh_size; mesh_size_=mesh_size;
} }
void raster_symbolizer::set_premultiplied(bool premultiplied)
{
premultiplied_=premultiplied;
}
boost::optional<bool> raster_symbolizer::premultiplied() const
{
return premultiplied_;
}
} }

View file

@ -180,10 +180,18 @@ public:
set_attr( sym_node, "mesh-size", sym.get_mesh_size() ); set_attr( sym_node, "mesh-size", sym.get_mesh_size() );
} }
if (sym.get_colorizer()) { if (sym.get_colorizer())
{
serialize_raster_colorizer(sym_node, sym.get_colorizer(), serialize_raster_colorizer(sym_node, sym.get_colorizer(),
explicit_defaults_); explicit_defaults_);
} }
boost::optional<bool> premultiplied = sym.premultiplied();
if (premultiplied)
{
set_attr( sym_node, "premultiplied", *sym.premultiplied());
}
serialize_symbolizer_base(sym_node, sym); serialize_symbolizer_base(sym_node, sym);
} }

View file

@ -85,6 +85,9 @@ def validate_pixels_are_premultiplied(image):
def test_compare_images(): def test_compare_images():
b = mapnik.Image.open('./images/support/b.png') b = mapnik.Image.open('./images/support/b.png')
b.premultiply() b.premultiply()
num_ops = len(mapnik.CompositeOp.names)
successes = []
fails = []
for name in mapnik.CompositeOp.names: for name in mapnik.CompositeOp.names:
a = mapnik.Image.open('./images/support/a.png') a = mapnik.Image.open('./images/support/a.png')
a.premultiply() a.premultiply()
@ -98,9 +101,16 @@ def test_compare_images():
if not validate_pixels_are_not_premultiplied(a): if not validate_pixels_are_not_premultiplied(a):
print '%s not validly demultiplied' % (name) print '%s not validly demultiplied' % (name)
a.save(actual) a.save(actual)
if not os.path.exists(expected):
print 'generating expected test image: %s' % expected
a.save(expected)
expected_im = mapnik.Image.open(expected) expected_im = mapnik.Image.open(expected)
# compare them # compare them
eq_(a.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected)) if a.tostring() == expected_im.tostring():
successes.append(name)
else:
fails.append('failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
eq_(len(successes),num_ops,'\n'+'\n'.join(fails))
b.demultiply() b.demultiply()
# b will be slightly modified by pre and then de multiplication rounding errors # b will be slightly modified by pre and then de multiplication rounding errors
# TODO - write test to ensure the image is 99% the same. # TODO - write test to ensure the image is 99% the same.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -14,6 +14,18 @@ def setup():
# from another directory we need to chdir() # from another directory we need to chdir()
os.chdir(execution_path('.')) os.chdir(execution_path('.'))
def test_raster_symbolizer():
s = mapnik.RasterSymbolizer()
eq_(s.comp_op,mapnik.CompositeOp.src_over) # note: mode is deprecated
eq_(s.scaling,mapnik.scaling_method.NEAR)
eq_(s.opacity,1.0)
eq_(s.colorizer,None)
eq_(s.filter_factor,-1)
eq_(s.mesh_size,16)
eq_(s.premultiplied,None)
s.premultiplied = True
eq_(s.premultiplied,True)
def test_line_pattern(): def test_line_pattern():
s = mapnik.LinePatternSymbolizer(mapnik.PathExpression('../data/images/dummy.png')) s = mapnik.LinePatternSymbolizer(mapnik.PathExpression('../data/images/dummy.png'))
eq_(s.filename, '../data/images/dummy.png') eq_(s.filename, '../data/images/dummy.png')

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -4,7 +4,7 @@
<Style name="white"> <Style name="white">
<Rule> <Rule>
<RasterSymbolizer opacity="1" scaling="bilinear" comp-op="src-over"/> <RasterSymbolizer />
</Rule> </Rule>
</Style> </Style>
<Layer name="white" <Layer name="white"

View file

@ -4,7 +4,7 @@
<Style name="white"> <Style name="white">
<Rule> <Rule>
<RasterSymbolizer opacity="1" scaling="bilinear" comp-op="src-over"/> <RasterSymbolizer premultiplied="false"/>
</Rule> </Rule>
</Style> </Style>
<Layer name="white" <Layer name="white"

View file

@ -11,7 +11,8 @@
srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"> srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over">
<StyleName>style</StyleName> <StyleName>style</StyleName>
<Datasource> <Datasource>
<!-- https://github.com/mapnik/mapnik/issues/1471 --> <!-- https://github.com/mapnik/mapnik/issues/1508 -->
<!-- note: this mis-reports it is premultiplied - it is not -->
<Parameter name="file">../../data/raster/nodata-edge.tif</Parameter> <Parameter name="file">../../data/raster/nodata-edge.tif</Parameter>
<Parameter name="type">raster</Parameter> <Parameter name="type">raster</Parameter>
<Parameter name="extent">-12329035.765216826,4508650.398543958,-12328653.027947057,4508957.346255356</Parameter> <Parameter name="extent">-12329035.765216826,4508650.398543958,-12328653.027947057,4508957.346255356</Parameter>

View file

@ -1,4 +1,4 @@
<Map srs="+init=EPSG:4326" background-color="white"> <Map srs="+init=epsg:4326" background-color="white">
<Style name="test"> <Style name="test">
<Rule> <Rule>
@ -6,10 +6,12 @@
</Rule> </Rule>
</Style> </Style>
<Layer name="test" srs="+init=EPSG:4326"> <Layer name="test" srs="+init=epsg:4326">
<StyleName>test</StyleName> <StyleName>test</StyleName>
<Datasource> <Datasource>
<Parameter name="file">../../data/raster/river.tiff</Parameter> <!-- https://github.com/mapnik/mapnik/issues/1508 -->
<!-- note: this mis-reports it is premultiplied - it is not -->
<Parameter name="file">../../data/raster/river_wgs.tiff</Parameter>
<Parameter name="type">gdal</Parameter> <Parameter name="type">gdal</Parameter>
</Datasource> </Datasource>
</Layer> </Layer>

View file

@ -0,0 +1,17 @@
<Map srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" background-color="rgba(255,255,255,1)">
<Style name="testmerc" filter-mode="first" >
<Rule>
<RasterSymbolizer opacity="1" scaling="bilinear" />
</Rule>
</Style>
<Layer name="testmerc"
srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over">
<StyleName>testmerc</StyleName>
<Datasource>
<!-- https://github.com/mapnik/mapnik/issues/1508 -->
<!-- note: this mis-reports it is premultiplied - it is not -->
<Parameter name="file">../../data/raster/river_merc.tiff</Parameter>
<Parameter name="type">gdal</Parameter>
</Datasource>
</Layer>
</Map>

View file

@ -1,4 +1,4 @@
<Map srs="+init=EPSG:4326" background-color="white"> <Map srs="+init=epsg:4326" background-color="white">
<Style name="test"> <Style name="test">
<Rule> <Rule>
@ -6,10 +6,10 @@
</Rule> </Rule>
</Style> </Style>
<Layer name="test" srs="+init=EPSG:4326"> <Layer name="test" srs="+init=epsg:4326">
<StyleName>test</StyleName> <StyleName>test</StyleName>
<Datasource> <Datasource>
<Parameter name="file">../../data/raster/river.tiff</Parameter> <Parameter name="file">../../data/raster/river_wgs.tiff</Parameter>
<Parameter name="type">raster</Parameter> <Parameter name="type">raster</Parameter>
<Parameter name="extent">0,0,256,210</Parameter> <Parameter name="extent">0,0,256,210</Parameter>
</Datasource> </Datasource>

View file

@ -0,0 +1,18 @@
<Map srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" background-color="rgba(255,255,255,1)">
<Style name="testmerc" filter-mode="first" >
<Rule>
<RasterSymbolizer opacity="1" scaling="bilinear" />
</Rule>
</Style>
<Layer name="testmerc"
srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over">
<StyleName>testmerc</StyleName>
<Datasource>
<!-- https://github.com/mapnik/mapnik/issues/1508 -->
<!-- note: this mis-reports it is premultiplied - it is not -->
<Parameter name="file">../../data/raster/river_merc.tiff</Parameter>
<Parameter name="extent">-8249238.098993212,-486119.1339340762,-8024337.037783274,-302066.9754826002</Parameter>
<Parameter name="type">raster</Parameter>
</Datasource>
</Layer>
</Map>

View file

@ -60,6 +60,8 @@ files = [
{'name': "tiff-nodata-edge-raster", 'sizes':[(600,400)]}, {'name': "tiff-nodata-edge-raster", 'sizes':[(600,400)]},
{'name': "tiff-opaque-edge-gdal", 'sizes':[(256,256)]}, {'name': "tiff-opaque-edge-gdal", 'sizes':[(256,256)]},
{'name': "tiff-opaque-edge-raster", 'sizes':[(256,256)]}, {'name': "tiff-opaque-edge-raster", 'sizes':[(256,256)]},
{'name': "tiff-opaque-edge-gdal2", 'sizes':[(600,400)]},
{'name': "tiff-opaque-edge-raster2", 'sizes':[(600,400)]},
{'name': "shieldsymbolizer-2"}, {'name': "shieldsymbolizer-2"},
{'name': "shieldsymbolizer-3"}, {'name': "shieldsymbolizer-3"},
{'name': "shieldsymbolizer-4"}, {'name': "shieldsymbolizer-4"},