Merge commit '57aa6dd05230876bf7c022d3554436e4d35de77f' into harfbuzz
Conflicts: tests/visual_tests/test.py
This commit is contained in:
commit
df7c2b5c0e
211 changed files with 7348 additions and 1040 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -8,6 +8,19 @@ For a complete change history, see the git log.
|
|||
|
||||
## Future
|
||||
|
||||
- Enabled default input plugin directory and fonts path to be set inherited from environment settings in
|
||||
python bindings to make it easier to run tests locally (#1594). New environment settings are:
|
||||
- MAPNIK_INPUT_PLUGINS_DIRECTORY
|
||||
- MAPNIK_FONT_DIRECTORY
|
||||
|
||||
- Added support for controlling rendering behavior of markers on multi-geometries `marker-multi-policy` (#1555,#1573)
|
||||
|
||||
- Added alternative PNG/ZLIB implementation (`miniz`) that can be enabled with `e=miniz` (#1554)
|
||||
|
||||
- Added support for setting zlib `Z_FIXED` strategy with format string: `png:z=fixed`
|
||||
|
||||
- Fixed handling of transparency level option in Octree-based PNG encoding (#1556)
|
||||
|
||||
- Faster rendering of rasters by reducing memory allocation of temporary buffers (#1516)
|
||||
|
||||
- Added ability to pass a pre-created collision detector to the cairo renderer (#1444)
|
||||
|
|
15
Makefile
15
Makefile
|
@ -1,3 +1,10 @@
|
|||
UNAME := $(shell uname)
|
||||
LINK_FIX=LD_LIBRARY_PATH
|
||||
ifeq ($(UNAME), Darwin)
|
||||
LINK_FIX=DYLD_LIBRARY_PATH
|
||||
else
|
||||
endif
|
||||
|
||||
all: mapnik
|
||||
|
||||
install:
|
||||
|
@ -31,6 +38,14 @@ test:
|
|||
@echo "*** Running python tests..."
|
||||
@python tests/run_tests.py -q
|
||||
|
||||
test-local:
|
||||
@echo "*** boostrapping local test environment..."
|
||||
export ${LINK_FIX}=`pwd`/src:${${LINK_FIX}} && \
|
||||
export PYTHONPATH=`pwd`/bindings/python/:${PYTHONPATH} && \
|
||||
export MAPNIK_FONT_DIRECTORY=`pwd`/fonts/dejavu-fonts-ttf-2.33/ttf/ && \
|
||||
export MAPNIK_INPUT_PLUGINS_DIRECTORY=`pwd`/plugins/input/ && \
|
||||
make test
|
||||
|
||||
demo:
|
||||
@echo "*** Running rundemo.cpp…"
|
||||
cd demo/c++; ./rundemo `mapnik-config --prefix`/lib/mapnik
|
||||
|
|
|
@ -329,7 +329,7 @@ opts.AddVariables(
|
|||
|
||||
BoolVariable('RENDERING_STATS', 'Output rendering statistics during style processing', 'False'),
|
||||
|
||||
#BoolVariable('SVG_RENDERER', 'build support for native svg renderer', 'False'),
|
||||
BoolVariable('SVG_RENDERER', 'build support for native svg renderer', 'False'),
|
||||
|
||||
# Variables for optional dependencies
|
||||
('GEOS_CONFIG', 'The path to the geos-config executable.', 'geos-config'),
|
||||
|
@ -430,7 +430,7 @@ pickle_store = [# Scons internal variables
|
|||
'CAIROMM_LIBPATHS',
|
||||
'CAIROMM_LINKFLAGS',
|
||||
'CAIROMM_CPPPATHS',
|
||||
#'SVG_RENDERER',
|
||||
'SVG_RENDERER',
|
||||
'SQLITE_LINKFLAGS',
|
||||
'BOOST_LIB_VERSION_FROM_HEADER'
|
||||
]
|
||||
|
@ -1750,8 +1750,8 @@ if not HELP_REQUESTED:
|
|||
|
||||
# not currently maintained
|
||||
# https://github.com/mapnik/mapnik/issues/1438
|
||||
#if env['SVG_RENDERER']:
|
||||
# SConscript('tests/cpp_tests/svg_renderer_tests/build.py')
|
||||
if env['SVG_RENDERER']:
|
||||
SConscript('tests/cpp_tests/svg_renderer_tests/build.py')
|
||||
|
||||
# install pkg-config script and mapnik-config script
|
||||
SConscript('utils/mapnik-config/build.py')
|
||||
|
|
|
@ -67,7 +67,8 @@ def bootstrap_env():
|
|||
bootstrap_env()
|
||||
|
||||
from _mapnik import *
|
||||
from paths import inputpluginspath, fontscollectionpath
|
||||
from paths import inputpluginspath
|
||||
from paths import fontscollectionpath
|
||||
|
||||
import printing
|
||||
printing.renderer = render
|
||||
|
@ -991,20 +992,27 @@ class _TextSymbolizer(TextSymbolizer,_injector):
|
|||
self.properties.wrap_width = wrap_width
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def mapnik_version_from_string(version_string):
|
||||
"""Return the Mapnik version from a string."""
|
||||
n = version_string.split('.')
|
||||
return (int(n[0]) * 100000) + (int(n[1]) * 100) + (int(n[2]));
|
||||
|
||||
def register_plugins(path=inputpluginspath):
|
||||
def register_plugins(path=None):
|
||||
"""Register plugins located by specified path"""
|
||||
if not path:
|
||||
if os.environ.has_key('MAPNIK_INPUT_PLUGINS_DIRECTORY'):
|
||||
path = os.environ.get('MAPNIK_INPUT_PLUGINS_DIRECTORY')
|
||||
else:
|
||||
path = inputpluginspath
|
||||
DatasourceCache.register_datasources(path)
|
||||
|
||||
def register_fonts(path=fontscollectionpath,valid_extensions=['.ttf','.otf','.ttc','.pfa','.pfb','.ttc','.dfont']):
|
||||
def register_fonts(path=None,valid_extensions=['.ttf','.otf','.ttc','.pfa','.pfb','.ttc','.dfont']):
|
||||
"""Recursively register fonts using path argument as base directory"""
|
||||
if not path:
|
||||
if os.environ.has_key('MAPNIK_FONT_DIRECTORY'):
|
||||
path = os.environ.get('MAPNIK_FONT_DIRECTORY')
|
||||
else:
|
||||
path = fontscollectionpath
|
||||
for dirpath, _, filenames in os.walk(path):
|
||||
for filename in filenames:
|
||||
if os.path.splitext(filename.lower())[1] in valid_extensions:
|
||||
|
|
|
@ -66,6 +66,7 @@ void export_grid()
|
|||
.def("height",&mapnik::grid::height)
|
||||
.def("view",&mapnik::grid::get_view)
|
||||
.def("get_pixel",&get_pixel)
|
||||
.def("clear",&mapnik::grid::clear)
|
||||
.def("encode",encode,
|
||||
( boost::python::arg("encoding")="utf", boost::python::arg("features")=true,boost::python::arg("resolution")=4 ),
|
||||
"Encode the grid as as optimized json\n"
|
||||
|
|
|
@ -235,6 +235,7 @@ void export_image()
|
|||
.def("demultiply",&image_32::demultiply)
|
||||
.def("set_pixel",&set_pixel)
|
||||
.def("get_pixel",&get_pixel)
|
||||
.def("clear",&image_32::clear)
|
||||
//TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3
|
||||
|
||||
.def("tostring",&tostring1)
|
||||
|
|
|
@ -89,6 +89,12 @@ void export_markers_symbolizer()
|
|||
.value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT)
|
||||
;
|
||||
|
||||
mapnik::enumeration_<mapnik::marker_multi_policy_e>("marker_multi_policy")
|
||||
.value("EACH",mapnik::MARKER_EACH_MULTI)
|
||||
.value("WHOLE",mapnik::MARKER_WHOLE_MULTI)
|
||||
.value("LARGEST",mapnik::MARKER_LARGEST_MULTI)
|
||||
;
|
||||
|
||||
class_<markers_symbolizer>("MarkersSymbolizer",
|
||||
init<>("Default Markers Symbolizer - circle"))
|
||||
.def (init<mapnik::path_expression_ptr>("<path expression ptr>"))
|
||||
|
@ -143,6 +149,10 @@ void export_markers_symbolizer()
|
|||
&markers_symbolizer::get_marker_placement,
|
||||
&markers_symbolizer::set_marker_placement,
|
||||
"Set/get the marker placement")
|
||||
.add_property("multi_policy",
|
||||
&markers_symbolizer::get_marker_multi_policy,
|
||||
&markers_symbolizer::set_marker_multi_policy,
|
||||
"Set/get the marker multi geometry rendering policy")
|
||||
.add_property("comp_op",
|
||||
&markers_symbolizer::comp_op,
|
||||
&markers_symbolizer::set_comp_op,
|
||||
|
|
|
@ -121,8 +121,7 @@ void grid2utf(T const& grid_type,
|
|||
// start counting at utf8 codepoint 32, aka space character
|
||||
boost::uint16_t codepoint = 32;
|
||||
|
||||
// TODO - use double?
|
||||
unsigned array_size = static_cast<unsigned int>(grid_type.width()/resolution);
|
||||
unsigned array_size = std::ceil(grid_type.width()/static_cast<float>(resolution));
|
||||
for (unsigned y = 0; y < grid_type.height(); y=y+resolution)
|
||||
{
|
||||
boost::uint16_t idx = 0;
|
||||
|
|
|
@ -59,9 +59,18 @@ struct default_color_converter_impl< rgb_t, hsl_t >
|
|||
bits32f temp_blue = channel_convert<bits32f>( get_color( src, blue_t() ));
|
||||
|
||||
bits32f hue, saturation, lightness;
|
||||
bits32f min_color, max_color;
|
||||
|
||||
bits32f min_color = std::min( temp_red, std::min( temp_green, temp_blue ));
|
||||
bits32f max_color = std::max( temp_red, std::max( temp_green, temp_blue ));
|
||||
if( temp_red < temp_green )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
if ( max_color - min_color < 0.001 )
|
||||
{
|
||||
|
|
|
@ -62,11 +62,13 @@ struct default_color_converter_impl< rgb_t, hsv_t >
|
|||
bits32f hue, saturation, value;
|
||||
bits32f min_color, max_color;
|
||||
|
||||
if( temp_red < temp_green ) {
|
||||
if( temp_red < temp_green )
|
||||
{
|
||||
min_color = std::min( temp_blue, temp_red );
|
||||
max_color = std::max( temp_blue, temp_green );
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
min_color = std::min( temp_blue, temp_green );
|
||||
max_color = std::max( temp_blue, temp_red );
|
||||
}
|
||||
|
|
2
deps/agg/include/agg_conv_adaptor_vcgen.h
vendored
2
deps/agg/include/agg_conv_adaptor_vcgen.h
vendored
|
@ -29,6 +29,7 @@ namespace agg
|
|||
|
||||
void rewind(unsigned) {}
|
||||
unsigned vertex(double*, double*) { return path_cmd_stop; }
|
||||
unsigned type() const { return 0; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -64,6 +65,7 @@ namespace agg
|
|||
}
|
||||
|
||||
unsigned vertex(double* x, double* y);
|
||||
unsigned type() const { return m_source->type(); }
|
||||
|
||||
private:
|
||||
// Prohibit copying
|
||||
|
|
1
deps/agg/include/agg_conv_adaptor_vpgen.h
vendored
1
deps/agg/include/agg_conv_adaptor_vpgen.h
vendored
|
@ -33,6 +33,7 @@ namespace agg
|
|||
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
unsigned type() const { return m_source->type(); }
|
||||
|
||||
private:
|
||||
conv_adaptor_vpgen(const conv_adaptor_vpgen<VertexSource, VPGen>&);
|
||||
|
|
1
deps/agg/include/agg_conv_clip_polygon.h
vendored
1
deps/agg/include/agg_conv_clip_polygon.h
vendored
|
@ -51,6 +51,7 @@ namespace agg
|
|||
double y1() const { return base_type::vpgen().y1(); }
|
||||
double x2() const { return base_type::vpgen().x2(); }
|
||||
double y2() const { return base_type::vpgen().y2(); }
|
||||
unsigned type() const { return base_type::type(); }
|
||||
|
||||
private:
|
||||
conv_clip_polygon(const conv_clip_polygon<VertexSource>&);
|
||||
|
|
1
deps/agg/include/agg_conv_clip_polyline.h
vendored
1
deps/agg/include/agg_conv_clip_polyline.h
vendored
|
@ -51,6 +51,7 @@ namespace agg
|
|||
double y1() const { return base_type::vpgen().y1(); }
|
||||
double x2() const { return base_type::vpgen().x2(); }
|
||||
double y2() const { return base_type::vpgen().y2(); }
|
||||
unsigned type() const { return base_type::type(); }
|
||||
|
||||
private:
|
||||
conv_clip_polyline(const conv_clip_polyline<VertexSource>&);
|
||||
|
|
2
deps/agg/include/agg_conv_smooth_poly1.h
vendored
2
deps/agg/include/agg_conv_smooth_poly1.h
vendored
|
@ -42,6 +42,7 @@ namespace agg
|
|||
|
||||
void smooth_value(double v) { base_type::generator().smooth_value(v); }
|
||||
double smooth_value() const { return base_type::generator().smooth_value(); }
|
||||
unsigned type() const { return base_type::type(); }
|
||||
|
||||
private:
|
||||
conv_smooth_poly1(const conv_smooth_poly1<VertexSource>&);
|
||||
|
@ -64,6 +65,7 @@ namespace agg
|
|||
|
||||
void smooth_value(double v) { m_smooth.generator().smooth_value(v); }
|
||||
double smooth_value() const { return m_smooth.generator().smooth_value(); }
|
||||
unsigned type() const { return m_smooth.type(); }
|
||||
|
||||
private:
|
||||
conv_smooth_poly1_curve(const conv_smooth_poly1_curve<VertexSource>&);
|
||||
|
|
|
@ -6,8 +6,8 @@ Import('env')
|
|||
base = './mapnik/'
|
||||
subdirs = ['','svg','wkt','grid','json','util','text','text/placements','text/formatting']
|
||||
|
||||
#if env['SVG_RENDERER']:
|
||||
# subdirs.append('svg/output')
|
||||
if env['SVG_RENDERER']:
|
||||
subdirs.append('svg/output')
|
||||
|
||||
if 'install' in COMMAND_LINE_TARGETS:
|
||||
for subdir in subdirs:
|
||||
|
|
|
@ -38,8 +38,27 @@ namespace mapnik
|
|||
template <typename Transform, typename Geometry>
|
||||
struct MAPNIK_DECL coord_transform
|
||||
{
|
||||
// SFINAE value_type detector
|
||||
template <typename T>
|
||||
struct void_type
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template <typename T, typename D, typename _ = void>
|
||||
struct select_value_type
|
||||
{
|
||||
typedef D type;
|
||||
};
|
||||
|
||||
template <typename T, typename D>
|
||||
struct select_value_type<T, D, typename void_type<typename T::value_type>::type>
|
||||
{
|
||||
typedef typename T::value_type type;
|
||||
};
|
||||
|
||||
typedef std::size_t size_type;
|
||||
//typedef typename Geometry::value_type value_type;
|
||||
typedef typename select_value_type<Geometry, void>::type value_type;
|
||||
|
||||
coord_transform(Transform const& t,
|
||||
Geometry & geom,
|
||||
|
@ -81,6 +100,11 @@ struct MAPNIK_DECL coord_transform
|
|||
geom_.rewind(pos);
|
||||
}
|
||||
|
||||
unsigned type() const
|
||||
{
|
||||
return static_cast<unsigned>(geom_.type());
|
||||
}
|
||||
|
||||
Geometry const& geom() const
|
||||
{
|
||||
return geom_;
|
||||
|
|
|
@ -296,7 +296,6 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
|||
{
|
||||
if (style->active(scale_denom))
|
||||
{
|
||||
std::clog << "triggering\n";
|
||||
// trigger any needed compositing ops
|
||||
p.start_style_processing(*style);
|
||||
p.end_style_processing(*style);
|
||||
|
@ -459,7 +458,7 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
|||
}
|
||||
else if (cache_features)
|
||||
{
|
||||
memory_datasource cache;
|
||||
memory_datasource cache(ds->type());
|
||||
featureset_ptr features = ds->features(q);
|
||||
if (features) {
|
||||
// Cache all features into the memory_datasource before rendering.
|
||||
|
|
|
@ -329,6 +329,70 @@ bool centroid(PathType & path, double & x, double & y)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Compute centroid over a set of paths
|
||||
template <typename Iter>
|
||||
bool centroid_geoms(Iter start, Iter end, double & x, double & y)
|
||||
{
|
||||
double x0 = 0.0;
|
||||
double y0 = 0.0;
|
||||
double x1 = 0.0;
|
||||
double y1 = 0.0;
|
||||
double start_x = x0;
|
||||
double start_y = y0;
|
||||
|
||||
bool empty = true;
|
||||
|
||||
double atmp = 0.0;
|
||||
double xtmp = 0.0;
|
||||
double ytmp = 0.0;
|
||||
unsigned count = 1;
|
||||
|
||||
while (start!=end)
|
||||
{
|
||||
typename Iter::value_type & path = *start++;
|
||||
path.rewind(0);
|
||||
unsigned command = path.vertex(&x0, &y0);
|
||||
if (command == SEG_END) continue;
|
||||
empty = false;
|
||||
|
||||
while (SEG_END != (command = path.vertex(&x1, &y1)))
|
||||
{
|
||||
double dx0 = x0 - start_x;
|
||||
double dy0 = y0 - start_y;
|
||||
double dx1 = x1 - start_x;
|
||||
double dy1 = y1 - start_y;
|
||||
double ai = dx0 * dy1 - dx1 * dy0;
|
||||
atmp += ai;
|
||||
xtmp += (dx1 + dx0) * ai;
|
||||
ytmp += (dy1 + dy0) * ai;
|
||||
x0 = x1;
|
||||
y0 = y1;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty ) return false;
|
||||
|
||||
if (count <= 2) {
|
||||
x = (start_x + x0) * 0.5;
|
||||
y = (start_y + y0) * 0.5;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (atmp != 0)
|
||||
{
|
||||
x = (xtmp/(3*atmp)) + start_x;
|
||||
y = (ytmp/(3*atmp)) + start_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = x0;
|
||||
y = y0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename PathType>
|
||||
bool hit_test(PathType & path, double x, double y, double tol)
|
||||
{
|
||||
|
|
|
@ -72,6 +72,11 @@ public:
|
|||
return painted_;
|
||||
}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
std::memset(data_.getData(),0,sizeof(mapnik::image_data_32::pixel_type)*data_.width()*data_.height());
|
||||
}
|
||||
|
||||
boost::optional<color> const& get_background() const;
|
||||
|
||||
void set_background(const color& c);
|
||||
|
|
|
@ -82,6 +82,8 @@ public:
|
|||
|
||||
~hit_grid() {}
|
||||
|
||||
void clear();
|
||||
|
||||
inline void painted(bool painted)
|
||||
{
|
||||
painted_ = painted;
|
||||
|
|
|
@ -112,8 +112,6 @@
|
|||
//convolve_rows_fixed<rgba32f_pixel_t>(src_view,kernel,src_view);
|
||||
// convolve_cols_fixed<rgba32f_pixel_t>(src_view,kernel,dst_view);
|
||||
|
||||
using namespace boost::gil;
|
||||
|
||||
namespace mapnik { namespace filter { namespace detail {
|
||||
|
||||
static const float blur_matrix[] = {0.1111,0.1111,0.1111,0.1111,0.1111,0.1111,0.1111,0.1111,0.1111};
|
||||
|
@ -123,12 +121,42 @@ static const float edge_detect_matrix[] = {0,1,0,1,-4,1,0,1,0 };
|
|||
|
||||
}
|
||||
|
||||
using boost::gil::rgba8_image_t;
|
||||
using boost::gil::rgba8_view_t;
|
||||
|
||||
template <typename Image>
|
||||
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<rgba8_pixel_t*>(img.raw_data()),
|
||||
img.width() * sizeof(rgba8_pixel_t));
|
||||
}
|
||||
|
||||
template <typename Image>
|
||||
struct double_buffer
|
||||
{
|
||||
boost::gil::rgba8_image_t dst_buffer;
|
||||
boost::gil::rgba8_view_t dst_view;
|
||||
boost::gil::rgba8_view_t src_view;
|
||||
|
||||
explicit double_buffer(Image & src)
|
||||
: dst_buffer(src.width(), src.height())
|
||||
, dst_view(view(dst_buffer))
|
||||
, src_view(rgba8_view(src)) {}
|
||||
|
||||
~double_buffer()
|
||||
{
|
||||
copy_pixels(dst_view, src_view);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Src, typename Dst, typename Conv>
|
||||
void process_channel_impl (Src const& src, Dst & dst, Conv const& k)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
typedef boost::gil::bits32f bits_type;
|
||||
using boost::gil::bits32f;
|
||||
|
||||
bits32f out_value =
|
||||
k[0]*src[0] + k[1]*src[1] + k[2]*src[2] +
|
||||
k[3]*src[3] + k[4]*src[4] + k[5]*src[5] +
|
||||
|
@ -175,8 +203,7 @@ void process_channel (Src const& src, Dst & dst, mapnik::filter::edge_detect)
|
|||
template <typename Src, typename Dst>
|
||||
void process_channel (Src const& src, Dst & dst, mapnik::filter::sobel)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
typedef boost::gil::bits32f bits_type;
|
||||
using boost::gil::bits32f;
|
||||
|
||||
bits32f x_gradient = (src[2] + 2*src[5] + src[8])
|
||||
- (src[0] + 2*src[3] + src[6]);
|
||||
|
@ -193,9 +220,12 @@ void process_channel (Src const& src, Dst & dst, mapnik::filter::sobel)
|
|||
|
||||
|
||||
|
||||
template <typename Src, typename Dst, typename FilterTag>
|
||||
void apply_convolution_3x3(Src const& src_view, Dst & dst_view, FilterTag filter_tag)
|
||||
template <typename Src, typename Dst, typename Filter>
|
||||
void apply_convolution_3x3(Src const& src_view, Dst & dst_view, Filter const& filter)
|
||||
{
|
||||
using boost::gil::bits32f;
|
||||
using boost::gil::point2;
|
||||
|
||||
// p0 p1 p2
|
||||
// p3 p4 p5
|
||||
// p6 p7 p8
|
||||
|
@ -251,7 +281,7 @@ void apply_convolution_3x3(Src const& src_view, Dst & dst_view, FilterTag filter
|
|||
p[1] = p[7];
|
||||
p[2] = p[8];
|
||||
|
||||
process_channel(p, (*dst_it)[i], filter_tag);
|
||||
process_channel(p, (*dst_it)[i], filter);
|
||||
}
|
||||
++src_loc.x();
|
||||
++dst_it;
|
||||
|
@ -298,7 +328,7 @@ void apply_convolution_3x3(Src const& src_view, Dst & dst_view, FilterTag filter
|
|||
p[5] = src_loc[loc21][i];
|
||||
p[8] = src_loc[loc22][i];
|
||||
}
|
||||
process_channel(p, (*dst_it)[i], filter_tag);
|
||||
process_channel(p, (*dst_it)[i], filter);
|
||||
}
|
||||
++dst_it;
|
||||
++src_loc.x();
|
||||
|
@ -346,36 +376,18 @@ void apply_convolution_3x3(Src const& src_view, Dst & dst_view, FilterTag filter
|
|||
p[7] = p[1];
|
||||
p[8] = p[2];
|
||||
|
||||
process_channel(p, (*dst_it)[i], filter_tag);
|
||||
process_channel(p, (*dst_it)[i], filter);
|
||||
}
|
||||
++src_loc.x();
|
||||
++dst_it;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Src, typename Dst,typename FilterTag>
|
||||
void apply_filter(Src const& src, Dst & dst, FilterTag filter_tag)
|
||||
template <typename Src, typename Filter>
|
||||
void apply_filter(Src & src, Filter const& filter)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
|
||||
(rgba8_pixel_t*) src.raw_data(),
|
||||
src.width()*4);
|
||||
rgba8_view_t dst_view = interleaved_view(dst.width(),dst.height(),
|
||||
(rgba8_pixel_t*) dst.raw_data(),
|
||||
dst.width()*4);
|
||||
apply_convolution_3x3(src_view,dst_view,filter_tag);
|
||||
}
|
||||
|
||||
template <typename Src, typename FilterTag>
|
||||
void apply_filter(Src & src, FilterTag filter_tag)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
|
||||
(rgba8_pixel_t*) src.raw_data(),
|
||||
src.width()*4);
|
||||
rgba8_image_t temp_buffer(src_view.dimensions());
|
||||
apply_convolution_3x3(src_view,boost::gil::view(temp_buffer), filter_tag);
|
||||
boost::gil::copy_pixels(view(temp_buffer), src_view);
|
||||
double_buffer<Src> tb(src);
|
||||
apply_convolution_3x3(tb.src_view, tb.dst_view, filter);
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
|
@ -386,17 +398,26 @@ void apply_filter(Src & src, agg_stack_blur const& op)
|
|||
agg::stack_blur_rgba32(pixf,op.rx,op.ry);
|
||||
}
|
||||
|
||||
|
||||
template <typename Src>
|
||||
void apply_filter(Src & src, gray)
|
||||
void apply_filter(Src & src, gray const& op)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
typedef pixel<channel_type<rgba8_view_t>::type, gray_layout_t> gray_pixel_t;
|
||||
|
||||
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
|
||||
(rgba8_pixel_t*) src.raw_data(),
|
||||
src.width()*4);
|
||||
boost::gil::copy_and_convert_pixels(color_converted_view<gray_pixel_t>(src_view), src_view);
|
||||
rgba8_view_t src_view = rgba8_view(src);
|
||||
|
||||
for (int y=0; y<src_view.height(); ++y)
|
||||
{
|
||||
rgba8_view_t::x_iterator src_it = src_view.row_begin(y);
|
||||
for (int x=0; x<src_view.width(); ++x)
|
||||
{
|
||||
// formula taken from boost/gil/color_convert.hpp:rgb_to_luminance
|
||||
uint8_t & r = get_color(src_it[x], red_t());
|
||||
uint8_t & g = get_color(src_it[x], green_t());
|
||||
uint8_t & b = get_color(src_it[x], blue_t());
|
||||
uint8_t v = uint8_t((4915 * r + 9667 * g + 1802 * b + 8192) >> 14);
|
||||
r = g = b = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Src, typename Dst>
|
||||
|
@ -428,51 +449,41 @@ void x_gradient_impl(Src const& src_view, Dst const& dst_view)
|
|||
}
|
||||
|
||||
template <typename Src>
|
||||
void apply_filter(Src & src, x_gradient)
|
||||
void apply_filter(Src & src, x_gradient const& op)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
|
||||
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
|
||||
(rgba8_pixel_t*) src.raw_data(),
|
||||
src.width()*4);
|
||||
|
||||
rgba8_image_t temp_buffer(src_view.dimensions());
|
||||
rgba8_view_t dst_view = view(temp_buffer);
|
||||
|
||||
x_gradient_impl(src_view, dst_view);
|
||||
boost::gil::copy_pixels(view(temp_buffer), src_view);
|
||||
double_buffer<Src> tb(src);
|
||||
x_gradient_impl(tb.src_view, tb.dst_view);
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
void apply_filter(Src & src, y_gradient)
|
||||
void apply_filter(Src & src, y_gradient const& op)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
|
||||
(rgba8_pixel_t*) src.raw_data(),
|
||||
src.width()*4);
|
||||
rgba8_image_t temp_buffer(src_view.dimensions());
|
||||
rgba8_view_t dst_view = view(temp_buffer);
|
||||
x_gradient_impl(rotated90ccw_view(src_view), rotated90ccw_view(dst_view));
|
||||
boost::gil::copy_pixels(view(temp_buffer), src_view);
|
||||
double_buffer<Src> tb(src);
|
||||
x_gradient_impl(rotated90ccw_view(tb.src_view),
|
||||
rotated90ccw_view(tb.dst_view));
|
||||
}
|
||||
|
||||
template <typename Src>
|
||||
void apply_filter(Src & src, invert)
|
||||
void apply_filter(Src & src, invert const& op)
|
||||
{
|
||||
using namespace boost::gil;
|
||||
|
||||
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
|
||||
(rgba8_pixel_t*) src.raw_data(),
|
||||
src.width()*4);
|
||||
rgba8_view_t src_view = rgba8_view(src);
|
||||
|
||||
for (int y=0; y<src_view.height(); ++y)
|
||||
{
|
||||
rgba8_view_t::x_iterator src_itr = src_view.row_begin(y);
|
||||
rgba8_view_t::x_iterator src_it = src_view.row_begin(y);
|
||||
for (int x=0; x<src_view.width(); ++x)
|
||||
{
|
||||
get_color(src_itr[x],red_t()) = channel_invert(get_color(src_itr[x],red_t()));
|
||||
get_color(src_itr[x],green_t()) = channel_invert(get_color(src_itr[x],green_t()));
|
||||
get_color(src_itr[x],blue_t()) = channel_invert(get_color(src_itr[x],blue_t()));
|
||||
get_color(src_itr[x],alpha_t()) = get_color(src_itr[x],alpha_t());
|
||||
// we only work with premultiplied source,
|
||||
// thus all color values must be <= alpha
|
||||
uint8_t a = get_color(src_it[x], alpha_t());
|
||||
uint8_t & r = get_color(src_it[x], red_t());
|
||||
uint8_t & g = get_color(src_it[x], green_t());
|
||||
uint8_t & b = get_color(src_it[x], blue_t());
|
||||
r = a - r;
|
||||
g = a - g;
|
||||
b = a - b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -484,9 +495,9 @@ struct filter_visitor : boost::static_visitor<void>
|
|||
: src_(src) {}
|
||||
|
||||
template <typename T>
|
||||
void operator () (T const& filter_tag)
|
||||
void operator () (T const& filter)
|
||||
{
|
||||
apply_filter(src_,filter_tag);
|
||||
apply_filter(src_, filter);
|
||||
}
|
||||
|
||||
Src & src_;
|
||||
|
|
|
@ -91,7 +91,12 @@ struct vector_markers_rasterizer_dispatch
|
|||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
if (path.type() == LineString)
|
||||
{
|
||||
if (!label::middle_point(path, x, y))
|
||||
return;
|
||||
}
|
||||
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
{
|
||||
if (!label::interior_position(path, x, y))
|
||||
return;
|
||||
|
@ -187,7 +192,12 @@ struct raster_markers_rasterizer_dispatch
|
|||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
if (path.type() == LineString)
|
||||
{
|
||||
if (!label::middle_point(path, x, y))
|
||||
return;
|
||||
}
|
||||
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
{
|
||||
if (!label::interior_position(path, x, y))
|
||||
return;
|
||||
|
@ -398,6 +408,68 @@ void setup_transform_scaling(agg::trans_affine & tr, box2d<double> const& bbox,
|
|||
}
|
||||
}
|
||||
|
||||
// Apply markers to a feature with multiple geometries
|
||||
template <typename Converter>
|
||||
void apply_markers_multi(feature_impl & feature, Converter& converter, markers_symbolizer const& sym)
|
||||
{
|
||||
std::size_t geom_count = feature.paths().size();
|
||||
if (geom_count == 1)
|
||||
{
|
||||
converter.apply(feature.paths()[0]);
|
||||
}
|
||||
else if (geom_count > 1)
|
||||
{
|
||||
marker_multi_policy_e multi_policy = sym.get_marker_multi_policy();
|
||||
marker_placement_e placement = sym.get_marker_placement();
|
||||
if (placement == MARKER_POINT_PLACEMENT &&
|
||||
multi_policy == MARKER_WHOLE_MULTI)
|
||||
{
|
||||
double x, y;
|
||||
if (label::centroid_geoms(feature.paths().begin(), feature.paths().end(), x, y))
|
||||
{
|
||||
geometry_type pt(Point);
|
||||
pt.move_to(x, y);
|
||||
// unset any clipping since we're now dealing with a point
|
||||
converter.template unset<clip_poly_tag>();
|
||||
converter.apply(pt);
|
||||
}
|
||||
}
|
||||
else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
|
||||
multi_policy == MARKER_LARGEST_MULTI)
|
||||
{
|
||||
// Only apply to path with largest envelope area
|
||||
// TODO: consider using true area for polygon types
|
||||
double maxarea = 0;
|
||||
geometry_type* largest = 0;
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
const box2d<double>& env = geom.envelope();
|
||||
double area = env.width() * env.height();
|
||||
if (area > maxarea)
|
||||
{
|
||||
maxarea = area;
|
||||
largest = &geom;
|
||||
}
|
||||
}
|
||||
if (largest)
|
||||
{
|
||||
converter.apply(*largest);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
|
||||
{
|
||||
MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
|
||||
}
|
||||
BOOST_FOREACH(geometry_type & path, feature.paths())
|
||||
{
|
||||
converter.apply(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //MAPNIK_MARKER_HELPERS_HPP
|
||||
|
|
|
@ -60,19 +60,34 @@ public:
|
|||
* converted to a positive value with similar magnitude, but
|
||||
* choosen to optimize marker placement. 0 = no markers
|
||||
*/
|
||||
markers_placement(Locator &locator, box2d<double> const& size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap)
|
||||
markers_placement(Locator &locator,
|
||||
box2d<double> const& size,
|
||||
agg::trans_affine const& tr,
|
||||
Detector &detector,
|
||||
double spacing,
|
||||
double max_error,
|
||||
bool allow_overlap)
|
||||
: locator_(locator),
|
||||
size_(size),
|
||||
tr_(tr),
|
||||
detector_(detector),
|
||||
max_error_(max_error),
|
||||
allow_overlap_(allow_overlap)
|
||||
allow_overlap_(allow_overlap),
|
||||
marker_width_((size_ * tr_).width()),
|
||||
done_(false),
|
||||
last_x(.0),
|
||||
last_y(.0),
|
||||
next_x(.0),
|
||||
next_y(.0),
|
||||
error_(.0),
|
||||
spacing_left_(.0),
|
||||
marker_nr_(0)
|
||||
{
|
||||
marker_width_ = (size_ * tr_).width();
|
||||
if (spacing >= 0)
|
||||
{
|
||||
spacing_ = spacing;
|
||||
} else if (spacing < 0)
|
||||
}
|
||||
else if (spacing < 0)
|
||||
{
|
||||
spacing_ = find_optimal_spacing(-spacing);
|
||||
}
|
||||
|
@ -104,7 +119,10 @@ public:
|
|||
*/
|
||||
bool get_point(double & x, double & y, double & angle, bool add_to_detector = true)
|
||||
{
|
||||
if (done_) return false;
|
||||
if (done_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
unsigned cmd;
|
||||
/* This functions starts at the position of the previous marker,
|
||||
walks along the path, counting how far it has to go in spacing_left.
|
||||
|
@ -120,7 +138,8 @@ public:
|
|||
{
|
||||
//First marker
|
||||
spacing_left_ = spacing_ / 2;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
spacing_left_ = spacing_;
|
||||
}
|
||||
|
@ -150,7 +169,7 @@ public:
|
|||
double segment_length = std::sqrt(dx * dx + dy * dy);
|
||||
if (segment_length <= spacing_left_)
|
||||
{
|
||||
//Segment is to short to place marker. Find next segment
|
||||
//Segment is too short to place marker. Find next segment
|
||||
spacing_left_ -= segment_length;
|
||||
last_x = next_x;
|
||||
last_y = next_y;
|
||||
|
@ -178,7 +197,8 @@ public:
|
|||
//Segment to short => Skip this segment
|
||||
set_spacing_left(segment_length + marker_width_/2); //Only moves forward
|
||||
continue;
|
||||
} else if (segment_length - spacing_left_ < marker_width_/2)
|
||||
}
|
||||
else if (segment_length - spacing_left_ < marker_width_/2)
|
||||
{
|
||||
//Segment is long enough, but we are to close to the end
|
||||
//Note: This function moves backwards. This could lead to an infinite
|
||||
|
@ -187,7 +207,8 @@ public:
|
|||
if (error_ == 0)
|
||||
{
|
||||
set_spacing_left(segment_length - marker_width_/2, true);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
//Skip this segment
|
||||
set_spacing_left(segment_length + marker_width_/2); //Only moves forward
|
||||
|
@ -217,13 +238,15 @@ private:
|
|||
agg::trans_affine tr_;
|
||||
Detector &detector_;
|
||||
double spacing_;
|
||||
double marker_width_;
|
||||
double max_error_;
|
||||
bool allow_overlap_;
|
||||
double marker_width_;
|
||||
|
||||
bool done_;
|
||||
double last_x, last_y;
|
||||
double next_x, next_y;
|
||||
double last_x;
|
||||
double last_y;
|
||||
double next_x;
|
||||
double next_y;
|
||||
/** If a marker could not be placed at the exact point where it should
|
||||
* go the next marker's distance will be a bit lower. */
|
||||
double error_;
|
||||
|
|
|
@ -46,6 +46,15 @@ enum marker_placement_enum {
|
|||
|
||||
DEFINE_ENUM( marker_placement_e, marker_placement_enum );
|
||||
|
||||
enum marker_multi_policy_enum {
|
||||
MARKER_EACH_MULTI, // each component in a multi gets its marker
|
||||
MARKER_WHOLE_MULTI, // consider all components of a multi as a whole
|
||||
MARKER_LARGEST_MULTI, // only the largest component of a multi gets a marker
|
||||
marker_multi_policy_enum_MAX
|
||||
};
|
||||
|
||||
DEFINE_ENUM( marker_multi_policy_e, marker_multi_policy_enum );
|
||||
|
||||
struct MAPNIK_DECL markers_symbolizer :
|
||||
public symbolizer_with_image, public symbolizer_base
|
||||
{
|
||||
|
@ -74,6 +83,8 @@ public:
|
|||
boost::optional<stroke> get_stroke() const;
|
||||
void set_marker_placement(marker_placement_e marker_p);
|
||||
marker_placement_e get_marker_placement() const;
|
||||
void set_marker_multi_policy(marker_multi_policy_e marker_p);
|
||||
marker_multi_policy_e get_marker_multi_policy() const;
|
||||
private:
|
||||
expression_ptr width_;
|
||||
expression_ptr height_;
|
||||
|
@ -86,6 +97,7 @@ private:
|
|||
boost::optional<float> opacity_;
|
||||
boost::optional<stroke> stroke_;
|
||||
marker_placement_e marker_p_;
|
||||
marker_multi_policy_e marker_mp_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ class MAPNIK_DECL memory_datasource : public datasource
|
|||
{
|
||||
friend class memory_featureset;
|
||||
public:
|
||||
memory_datasource();
|
||||
memory_datasource(datasource::datasource_t type=datasource::Vector);
|
||||
virtual ~memory_datasource();
|
||||
void push(feature_ptr feature);
|
||||
datasource::datasource_t type() const;
|
||||
|
@ -50,6 +50,7 @@ public:
|
|||
private:
|
||||
std::vector<feature_ptr> features_;
|
||||
mapnik::layer_descriptor desc_;
|
||||
datasource::datasource_t type_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#define MAPNIK_MEMORY_FEATURESET_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/memory_datasource.hpp>
|
||||
|
||||
// boost
|
||||
|
@ -38,13 +37,15 @@ public:
|
|||
memory_featureset(box2d<double> const& bbox, memory_datasource const& ds)
|
||||
: bbox_(bbox),
|
||||
pos_(ds.features_.begin()),
|
||||
end_(ds.features_.end())
|
||||
end_(ds.features_.end()),
|
||||
type_(ds.type())
|
||||
{}
|
||||
|
||||
memory_featureset(box2d<double> const& bbox, std::vector<feature_ptr> const& features)
|
||||
: bbox_(bbox),
|
||||
pos_(features.begin()),
|
||||
end_(features.end())
|
||||
end_(features.end()),
|
||||
type_(datasource::Vector)
|
||||
{}
|
||||
|
||||
virtual ~memory_featureset() {}
|
||||
|
@ -53,20 +54,23 @@ public:
|
|||
{
|
||||
while (pos_ != end_)
|
||||
{
|
||||
for (unsigned i=0; i<(*pos_)->num_geometries();++i)
|
||||
if (type_ == datasource::Raster)
|
||||
{
|
||||
geometry_type & geom = (*pos_)->get_geometry(i);
|
||||
|
||||
MAPNIK_LOG_DEBUG(memory_featureset) << "memory_featureset: BBox=" << bbox_ << ",Envelope=" << geom.envelope();
|
||||
|
||||
if (bbox_.intersects(geom.envelope()))
|
||||
return *pos_++;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned i=0; i<(*pos_)->num_geometries();++i)
|
||||
{
|
||||
return *pos_++;
|
||||
geometry_type & geom = (*pos_)->get_geometry(i);
|
||||
if (bbox_.intersects(geom.envelope()))
|
||||
{
|
||||
return *pos_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
++pos_;
|
||||
}
|
||||
|
||||
return feature_ptr();
|
||||
}
|
||||
|
||||
|
@ -74,6 +78,7 @@ private:
|
|||
box2d<double> bbox_;
|
||||
std::vector<feature_ptr>::const_iterator pos_;
|
||||
std::vector<feature_ptr>::const_iterator end_;
|
||||
datasource::datasource_t type_;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
83
include/mapnik/miniz_png.hpp
Normal file
83
include/mapnik/miniz_png.hpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 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_MINIZ_PNG_HPP
|
||||
#define MAPNIK_MINIZ_PNG_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/palette.hpp>
|
||||
|
||||
// stl
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
/* miniz.c porting issues:
|
||||
- duplicate symbols in python bindings require moving miniz.c include to just cpp file
|
||||
- due to http://code.google.com/p/miniz/issues/detail?id=7
|
||||
- avoiding including miniz.c here requires fwd declaring the two structs below
|
||||
- being able to fwd declare requires removing typedef from struct declarations in miniz.c
|
||||
- being able to fwd declare also requires using pointers to structs
|
||||
*/
|
||||
|
||||
// TODO: try using #define MINIZ_HEADER_FILE_ONLY
|
||||
struct tdefl_output_buffer;
|
||||
struct tdefl_compressor;
|
||||
|
||||
namespace mapnik { namespace MiniZ {
|
||||
|
||||
using mapnik::rgb;
|
||||
|
||||
class PNGWriter {
|
||||
|
||||
public:
|
||||
PNGWriter(int level, int strategy);
|
||||
~PNGWriter();
|
||||
private:
|
||||
inline void writeUInt32BE(unsigned char *target, unsigned int value);
|
||||
size_t startChunk(const unsigned char header[], size_t length);
|
||||
void finishChunk(size_t start);
|
||||
public:
|
||||
void writeIHDR(unsigned int width, unsigned int height, unsigned char pixel_depth);
|
||||
void writePLTE(std::vector<rgb> const& palette);
|
||||
void writetRNS(std::vector<unsigned> const& alpha);
|
||||
template<typename T>
|
||||
void writeIDAT(T const& image);
|
||||
template<typename T>
|
||||
void writeIDATStripAlpha(T const& image);
|
||||
void writeIEND();
|
||||
void toStream(std::ostream& stream);
|
||||
|
||||
private:
|
||||
tdefl_compressor *compressor;
|
||||
tdefl_output_buffer *buffer;
|
||||
static const unsigned char preamble[];
|
||||
static const unsigned char IHDR_tpl[];
|
||||
static const unsigned char PLTE_tpl[];
|
||||
static const unsigned char tRNS_tpl[];
|
||||
static const unsigned char IDAT_tpl[];
|
||||
static const unsigned char IEND_tpl[];
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // MAPNIK_MINIZ_PNG_HPP
|
|
@ -56,7 +56,7 @@ class octree : private boost::noncopyable
|
|||
{
|
||||
struct node
|
||||
{
|
||||
node ()
|
||||
node()
|
||||
: reds(0),
|
||||
greens(0),
|
||||
blues(0),
|
||||
|
@ -68,14 +68,22 @@ class octree : private boost::noncopyable
|
|||
memset(&children_[0],0,sizeof(children_));
|
||||
}
|
||||
|
||||
~node ()
|
||||
~node()
|
||||
{
|
||||
for (unsigned i = 0;i < 8; ++i) {
|
||||
if (children_[i] != 0) delete children_[i],children_[i]=0;
|
||||
for (unsigned i = 0;i < 8; ++i)
|
||||
{
|
||||
if (children_[i] != 0)
|
||||
{
|
||||
delete children_[i];
|
||||
children_[i]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_leaf() const { return count == 0; }
|
||||
bool is_leaf() const
|
||||
{
|
||||
return count == 0;
|
||||
}
|
||||
node * children_[8];
|
||||
boost::uint64_t reds;
|
||||
boost::uint64_t greens;
|
||||
|
@ -83,8 +91,8 @@ class octree : private boost::noncopyable
|
|||
unsigned count;
|
||||
double reduce_cost;
|
||||
unsigned count_cum;
|
||||
byte children_count;
|
||||
byte index;
|
||||
byte children_count;
|
||||
byte index;
|
||||
};
|
||||
struct node_cmp
|
||||
{
|
||||
|
@ -99,7 +107,6 @@ class octree : private boost::noncopyable
|
|||
unsigned colors_;
|
||||
unsigned offset_;
|
||||
unsigned leaf_level_;
|
||||
bool has_alfa_;
|
||||
|
||||
public:
|
||||
explicit octree(unsigned max_colors=256)
|
||||
|
@ -107,11 +114,13 @@ public:
|
|||
colors_(0),
|
||||
offset_(0),
|
||||
leaf_level_(InsertPolicy::MAX_LEVELS),
|
||||
has_alfa_(false),
|
||||
root_(new node())
|
||||
{}
|
||||
|
||||
~octree() { delete root_;}
|
||||
~octree()
|
||||
{
|
||||
delete root_;
|
||||
}
|
||||
|
||||
unsigned colors()
|
||||
{
|
||||
|
@ -133,21 +142,12 @@ public:
|
|||
return offset_;
|
||||
}
|
||||
|
||||
void hasAlfa(bool v)
|
||||
{
|
||||
has_alfa_=v;
|
||||
}
|
||||
|
||||
bool hasAlfa()
|
||||
{
|
||||
return has_alfa_;
|
||||
}
|
||||
|
||||
void insert(T const& data)
|
||||
{
|
||||
unsigned level = 0;
|
||||
node * cur_node = root_;
|
||||
while (true) {
|
||||
while (true)
|
||||
{
|
||||
cur_node->count_cum++;
|
||||
cur_node->reds += data.r;
|
||||
cur_node->greens += data.g;
|
||||
|
@ -163,7 +163,8 @@ public:
|
|||
}
|
||||
|
||||
unsigned idx = InsertPolicy::index_from_level(level,data);
|
||||
if (cur_node->children_[idx] == 0) {
|
||||
if (cur_node->children_[idx] == 0)
|
||||
{
|
||||
cur_node->children_count++;
|
||||
cur_node->children_[idx] = new node();
|
||||
if (level < leaf_level_-1)
|
||||
|
@ -183,7 +184,9 @@ public:
|
|||
while (cur_node)
|
||||
{
|
||||
if (cur_node->children_count == 0)
|
||||
{
|
||||
return cur_node->index + offset_;
|
||||
}
|
||||
unsigned idx = InsertPolicy::index_from_level(level,c);
|
||||
cur_node = cur_node->children_[idx];
|
||||
++level;
|
||||
|
@ -193,11 +196,6 @@ public:
|
|||
|
||||
void create_palette(std::vector<rgb> & palette)
|
||||
{
|
||||
if (has_alfa_)
|
||||
{
|
||||
max_colors_--;
|
||||
palette.push_back(rgb(0,0,0));
|
||||
}
|
||||
reduce();
|
||||
palette.reserve(colors_);
|
||||
create_palette(palette, root_);
|
||||
|
@ -207,23 +205,26 @@ public:
|
|||
{
|
||||
r->reduce_cost = 0;
|
||||
if (r->children_count==0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double mean_r = static_cast<double>(r->reds / r->count_cum);
|
||||
double mean_g = static_cast<double>(r->greens / r->count_cum);
|
||||
double mean_b = static_cast<double>(r->blues / r->count_cum);
|
||||
for (unsigned idx=0; idx < 8; ++idx) if (r->children_[idx] != 0)
|
||||
{
|
||||
double dr,dg,db;
|
||||
computeCost(r->children_[idx]);
|
||||
|
||||
dr = r->children_[idx]->reds / r->children_[idx]->count_cum - mean_r;
|
||||
dg = r->children_[idx]->greens / r->children_[idx]->count_cum - mean_g;
|
||||
db = r->children_[idx]->blues / r->children_[idx]->count_cum - mean_b;
|
||||
|
||||
r->reduce_cost += r->children_[idx]->reduce_cost;
|
||||
r->reduce_cost += (dr*dr + dg*dg + db*db) * r->children_[idx]->count_cum;
|
||||
}
|
||||
for (unsigned idx=0; idx < 8; ++idx)
|
||||
{
|
||||
if (r->children_[idx] != 0)
|
||||
{
|
||||
double dr,dg,db;
|
||||
computeCost(r->children_[idx]);
|
||||
dr = r->children_[idx]->reds / r->children_[idx]->count_cum - mean_r;
|
||||
dg = r->children_[idx]->greens / r->children_[idx]->count_cum - mean_g;
|
||||
db = r->children_[idx]->blues / r->children_[idx]->count_cum - mean_b;
|
||||
r->reduce_cost += r->children_[idx]->reduce_cost;
|
||||
r->reduce_cost += (dr*dr + dg*dg + db*db) * r->children_[idx]->count_cum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reduce()
|
||||
|
@ -236,30 +237,39 @@ public:
|
|||
{
|
||||
std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
|
||||
}
|
||||
while ( colors_ > max_colors_ && colors_ > 1)
|
||||
while (colors_ > max_colors_ && colors_ > 1)
|
||||
{
|
||||
while (leaf_level_ >0 && reducible_[leaf_level_-1].size() == 0)
|
||||
{
|
||||
--leaf_level_;
|
||||
}
|
||||
|
||||
if (leaf_level_ <= 0) return;
|
||||
if (leaf_level_ <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// select best of all reducible:
|
||||
unsigned red_idx = leaf_level_-1;
|
||||
unsigned bestv = (*reducible_[red_idx].begin())->reduce_cost;
|
||||
for(unsigned i=red_idx; i>=InsertPolicy::MIN_LEVELS; i--) if (!reducible_[i].empty()){
|
||||
for(unsigned i=red_idx; i>=InsertPolicy::MIN_LEVELS; i--)
|
||||
{
|
||||
if (!reducible_[i].empty())
|
||||
{
|
||||
node *nd = *reducible_[i].begin();
|
||||
unsigned gch = 0;
|
||||
for(unsigned idx=0; idx<8; idx++){
|
||||
for(unsigned idx=0; idx<8; idx++)
|
||||
{
|
||||
if (nd->children_[idx])
|
||||
gch += nd->children_[idx]->children_count;
|
||||
}
|
||||
if (gch==0 && nd->reduce_cost < bestv){
|
||||
if (gch==0 && nd->reduce_cost < bestv)
|
||||
{
|
||||
bestv = static_cast<unsigned>(nd->reduce_cost);
|
||||
red_idx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typename std::deque<node*>::iterator pos = reducible_[red_idx].begin();
|
||||
node * cur_node = *pos;
|
||||
|
@ -297,7 +307,9 @@ public:
|
|||
for (unsigned i=0; i < 8 ;++i)
|
||||
{
|
||||
if (itr->children_[i] != 0)
|
||||
{
|
||||
create_palette(palette, itr->children_[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
|
|
@ -137,8 +137,8 @@ public:
|
|||
const std::vector<rgb>& palette() const;
|
||||
const std::vector<unsigned>& alphaTable() const;
|
||||
|
||||
unsigned quantize(rgba const& c) const;
|
||||
inline unsigned quantize(unsigned const& c) const
|
||||
unsigned char quantize(rgba const& c) const;
|
||||
inline unsigned char quantize(unsigned const& c) const
|
||||
{
|
||||
rgba_hash_table::const_iterator it = color_hashmap_.find(c);
|
||||
if (it != color_hashmap_.end())
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <mapnik/palette.hpp>
|
||||
#include <mapnik/octree.hpp>
|
||||
#include <mapnik/hextree.hpp>
|
||||
#include <mapnik/miniz_png.hpp>
|
||||
#include <mapnik/image_data.hpp>
|
||||
// zlib
|
||||
#include <zlib.h>
|
||||
|
@ -56,8 +57,32 @@ void flush_data (png_structp png_ptr)
|
|||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void save_as_png(T1 & file , T2 const& image, int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY)
|
||||
void save_as_png(T1 & file,
|
||||
T2 const& image,
|
||||
int compression = Z_DEFAULT_COMPRESSION,
|
||||
int strategy = Z_DEFAULT_STRATEGY,
|
||||
int trans_mode = -1,
|
||||
bool use_miniz = false)
|
||||
|
||||
{
|
||||
if (use_miniz)
|
||||
{
|
||||
MiniZ::PNGWriter writer(compression,strategy);
|
||||
if (trans_mode == 0)
|
||||
{
|
||||
writer.writeIHDR(image.width(), image.height(), 24);
|
||||
writer.writeIDATStripAlpha(image);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.writeIHDR(image.width(), image.height(), 32);
|
||||
writer.writeIDAT(image);
|
||||
}
|
||||
writer.writeIEND();
|
||||
writer.toStream(file);
|
||||
return;
|
||||
}
|
||||
|
||||
png_voidp error_ptr=0;
|
||||
png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
error_ptr,0, 0);
|
||||
|
@ -91,32 +116,35 @@ void save_as_png(T1 & file , T2 const& image, int compression = Z_DEFAULT_COMPRE
|
|||
png_set_compression_buffer_size(png_ptr, 32768);
|
||||
|
||||
png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8,
|
||||
PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
|
||||
(trans_mode == 0) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
for (unsigned i=0;i<image.height();i++)
|
||||
png_bytep row_pointers[image.height()];
|
||||
for (unsigned int i = 0; i < image.height(); i++)
|
||||
{
|
||||
png_write_row(png_ptr,(png_bytep)image.getRow(i));
|
||||
row_pointers[i] = (png_bytep)image.getRow(i);
|
||||
}
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
png_set_rows(png_ptr, info_ptr, (png_bytepp)&row_pointers);
|
||||
png_write_png(png_ptr, info_ptr, (trans_mode == 0) ? PNG_TRANSFORM_STRIP_FILLER_AFTER : PNG_TRANSFORM_IDENTITY, NULL);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void reduce_8 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned limits[], unsigned levels, std::vector<unsigned> & alpha)
|
||||
void reduce_8(T const& in,
|
||||
image_data_8 & out,
|
||||
octree<rgb> trees[],
|
||||
unsigned limits[],
|
||||
unsigned levels,
|
||||
std::vector<unsigned> & alpha)
|
||||
{
|
||||
unsigned width = in.width();
|
||||
unsigned height = in.height();
|
||||
|
||||
//unsigned alphaCount[alpha.size()];
|
||||
std::vector<unsigned> alphaCount(alpha.size());
|
||||
for(unsigned i=0; i<alpha.size(); i++)
|
||||
{
|
||||
alpha[i] = 0;
|
||||
alphaCount[i] = 0;
|
||||
}
|
||||
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
mapnik::image_data_32::pixel_type const * row = in.getRow(y);
|
||||
|
@ -127,8 +155,10 @@ void reduce_8 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned l
|
|||
mapnik::rgb c(U2RED(val), U2GREEN(val), U2BLUE(val));
|
||||
byte index = 0;
|
||||
int idx = -1;
|
||||
for(int j=levels-1; j>0; j--){
|
||||
if (U2ALPHA(val)>=limits[j] && trees[j].colors()>0) {
|
||||
for(int j=levels-1; j>0; j--)
|
||||
{
|
||||
if (U2ALPHA(val)>=limits[j] && trees[j].colors()>0)
|
||||
{
|
||||
index = idx = trees[j].quantize(c);
|
||||
break;
|
||||
}
|
||||
|
@ -144,37 +174,43 @@ void reduce_8 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned l
|
|||
for(unsigned i=0; i<alpha.size(); i++)
|
||||
{
|
||||
if (alphaCount[i]!=0)
|
||||
{
|
||||
alpha[i] /= alphaCount[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void reduce_4 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned limits[], unsigned levels, std::vector<unsigned> & alpha)
|
||||
void reduce_4(T const& in,
|
||||
image_data_8 & out,
|
||||
octree<rgb> trees[],
|
||||
unsigned limits[],
|
||||
unsigned levels,
|
||||
std::vector<unsigned> & alpha)
|
||||
{
|
||||
unsigned width = in.width();
|
||||
unsigned height = in.height();
|
||||
|
||||
//unsigned alphaCount[alpha.size()];
|
||||
std::vector<unsigned> alphaCount(alpha.size());
|
||||
for(unsigned i=0; i<alpha.size(); i++)
|
||||
{
|
||||
alpha[i] = 0;
|
||||
alphaCount[i] = 0;
|
||||
}
|
||||
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
mapnik::image_data_32::pixel_type const * row = in.getRow(y);
|
||||
mapnik::image_data_8::pixel_type * row_out = out.getRow(y);
|
||||
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
unsigned val = row[x];
|
||||
mapnik::rgb c(U2RED(val), U2GREEN(val), U2BLUE(val));
|
||||
byte index = 0;
|
||||
int idx=-1;
|
||||
for(int j=levels-1; j>0; j--){
|
||||
if (U2ALPHA(val)>=limits[j] && trees[j].colors()>0) {
|
||||
for(int j=levels-1; j>0; j--)
|
||||
{
|
||||
if (U2ALPHA(val)>=limits[j] && trees[j].colors()>0)
|
||||
{
|
||||
index = idx = trees[j].quantize(c);
|
||||
break;
|
||||
}
|
||||
|
@ -184,20 +220,29 @@ void reduce_4 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned li
|
|||
alpha[idx]+=U2ALPHA(val);
|
||||
alphaCount[idx]++;
|
||||
}
|
||||
if (x%2 == 0) index = index<<4;
|
||||
if (x%2 == 0)
|
||||
{
|
||||
index = index<<4;
|
||||
}
|
||||
row_out[x>>1] |= index;
|
||||
}
|
||||
}
|
||||
for(unsigned i=0; i<alpha.size(); i++)
|
||||
{
|
||||
if (alphaCount[i]!=0)
|
||||
{
|
||||
alpha[i] /= alphaCount[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1-bit but only one color.
|
||||
template <typename T>
|
||||
void reduce_1(T const&, image_data_8 & out, octree<rgb> /*trees*/[], unsigned /*limits*/[], std::vector<unsigned> & /*alpha*/)
|
||||
void reduce_1(T const&,
|
||||
image_data_8 & out,
|
||||
octree<rgb> /*trees*/[],
|
||||
unsigned /*limits*/[],
|
||||
std::vector<unsigned> & /*alpha*/)
|
||||
{
|
||||
out.set(0); // only one color!!!
|
||||
}
|
||||
|
@ -210,13 +255,31 @@ void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
|
|||
unsigned color_depth,
|
||||
int compression,
|
||||
int strategy,
|
||||
std::vector<unsigned> const&alpha)
|
||||
std::vector<unsigned> const&alpha,
|
||||
bool use_miniz)
|
||||
{
|
||||
if (use_miniz)
|
||||
{
|
||||
MiniZ::PNGWriter writer(compression,strategy);
|
||||
// image.width()/height() does not reflect the actual image dimensions; it
|
||||
// refers to the quantized scanlines.
|
||||
writer.writeIHDR(width, height, color_depth);
|
||||
writer.writePLTE(palette);
|
||||
writer.writetRNS(alpha);
|
||||
writer.writeIDAT(image);
|
||||
writer.writeIEND();
|
||||
writer.toStream(file);
|
||||
return;
|
||||
}
|
||||
|
||||
png_voidp error_ptr=0;
|
||||
png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
error_ptr,0, 0);
|
||||
|
||||
if (!png_ptr) return;
|
||||
if (!png_ptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// switch on optimization only if supported
|
||||
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
|
||||
|
@ -260,10 +323,14 @@ void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
|
|||
{
|
||||
trans[i]=alpha[i];
|
||||
if (alpha[i]<255)
|
||||
{
|
||||
alphaSize = i+1;
|
||||
}
|
||||
}
|
||||
if (alphaSize>0)
|
||||
{
|
||||
png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
@ -277,8 +344,13 @@ void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
|
|||
}
|
||||
|
||||
template <typename T1,typename T2>
|
||||
void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 256,
|
||||
int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY, int trans_mode = -1)
|
||||
void save_as_png8_oct(T1 & file,
|
||||
T2 const& image,
|
||||
const unsigned max_colors = 256,
|
||||
int compression = Z_DEFAULT_COMPRESSION,
|
||||
int strategy = Z_DEFAULT_STRATEGY,
|
||||
int trans_mode = -1,
|
||||
bool use_miniz = false)
|
||||
{
|
||||
// number of alpha ranges in png8 format; 2 results in smallest image with binary transparency
|
||||
// 3 is minimum for semitransparency, 4 is recommended, anything else is worse
|
||||
|
@ -288,70 +360,117 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
|
|||
unsigned alphaHist[256];//transparency histogram
|
||||
unsigned semiCount = 0;//sum of semitransparent pixels
|
||||
unsigned meanAlpha = 0;
|
||||
for(int i=0; i<256; i++){
|
||||
alphaHist[i] = 0;
|
||||
|
||||
if (trans_mode == 0)
|
||||
{
|
||||
meanAlpha = 255;
|
||||
}
|
||||
for (unsigned y = 0; y < height; ++y){
|
||||
for (unsigned x = 0; x < width; ++x){
|
||||
unsigned val = U2ALPHA((unsigned)image.getRow(y)[x]);
|
||||
if (trans_mode==0)
|
||||
val=255;
|
||||
alphaHist[val]++;
|
||||
meanAlpha += val;
|
||||
if (val>0 && val<255)
|
||||
semiCount++;
|
||||
else
|
||||
{
|
||||
for(int i=0; i<256; i++)
|
||||
{
|
||||
alphaHist[i] = 0;
|
||||
}
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
unsigned val = U2ALPHA((unsigned)image.getRow(y)[x]);
|
||||
alphaHist[val]++;
|
||||
meanAlpha += val;
|
||||
if (val>0 && val<255)
|
||||
{
|
||||
semiCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
meanAlpha /= width*height;
|
||||
}
|
||||
meanAlpha /= width*height;
|
||||
|
||||
// transparency ranges division points
|
||||
unsigned limits[MAX_OCTREE_LEVELS+1];
|
||||
limits[0] = 0;
|
||||
limits[1] = (alphaHist[0]>0)?1:0;
|
||||
limits[1] = (trans_mode!=0 && alphaHist[0]>0)?1:0;
|
||||
limits[TRANSPARENCY_LEVELS] = 256;
|
||||
unsigned alphaHistSum = 0;
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
|
||||
for(unsigned j=2; j<TRANSPARENCY_LEVELS; j++)
|
||||
{
|
||||
limits[j] = limits[1];
|
||||
for(unsigned i=1; i<256; i++){
|
||||
alphaHistSum += alphaHist[i];
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++){
|
||||
if (alphaHistSum<semiCount*(j)/4)
|
||||
limits[j] = i;
|
||||
}
|
||||
if (trans_mode != 0)
|
||||
{
|
||||
unsigned alphaHistSum = 0;
|
||||
for(unsigned i=1; i<256; i++)
|
||||
{
|
||||
alphaHistSum += alphaHist[i];
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
|
||||
{
|
||||
if (alphaHistSum<semiCount*(j)/4)
|
||||
{
|
||||
limits[j] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// avoid too wide full transparent range
|
||||
if (limits[1]>256/(TRANSPARENCY_LEVELS-1))
|
||||
{
|
||||
limits[1]=256/(TRANSPARENCY_LEVELS-1);
|
||||
}
|
||||
// avoid too wide full opaque range
|
||||
if (limits[TRANSPARENCY_LEVELS-1]<212)
|
||||
{
|
||||
limits[TRANSPARENCY_LEVELS-1]=212;
|
||||
if (TRANSPARENCY_LEVELS==2) {
|
||||
}
|
||||
if (TRANSPARENCY_LEVELS==2)
|
||||
{
|
||||
limits[1]=127;
|
||||
}
|
||||
// estimated number of colors from palette assigned to chosen ranges
|
||||
unsigned cols[MAX_OCTREE_LEVELS];
|
||||
// count colors
|
||||
for(unsigned j=1; j<=TRANSPARENCY_LEVELS; j++) {
|
||||
cols[j-1] = 0;
|
||||
for(unsigned i=limits[j-1]; i<limits[j]; i++){
|
||||
cols[j-1] += alphaHist[i];
|
||||
if (trans_mode == 0)
|
||||
{
|
||||
for (unsigned j=0; j<TRANSPARENCY_LEVELS; j++)
|
||||
{
|
||||
cols[j] = 0;
|
||||
}
|
||||
cols[TRANSPARENCY_LEVELS-1] = width * height;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned j=0; j<TRANSPARENCY_LEVELS; j++)
|
||||
{
|
||||
cols[j] = 0;
|
||||
for (unsigned i=limits[j]; i<limits[j+1]; i++)
|
||||
{
|
||||
cols[j] += alphaHist[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned divCoef = width*height-cols[0];
|
||||
if (divCoef==0) divCoef = 1;
|
||||
if (divCoef==0)
|
||||
{
|
||||
divCoef = 1;
|
||||
}
|
||||
cols[0] = cols[0]>0?1:0; // fully transparent color (one or not at all)
|
||||
|
||||
if (max_colors>=64) {
|
||||
if (max_colors>=64)
|
||||
{
|
||||
// give chance less populated but not empty cols to have at least few colors(12)
|
||||
unsigned minCols = (12+1)*divCoef/(max_colors-cols[0]);
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++) if (cols[j]>12 && cols[j]<minCols) {
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
|
||||
{
|
||||
if (cols[j]>12 && cols[j]<minCols)
|
||||
{
|
||||
divCoef += minCols-cols[j];
|
||||
cols[j] = minCols;
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned usedColors = cols[0];
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS-1; j++){
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS-1; j++)
|
||||
{
|
||||
cols[j] = cols[j]*(max_colors-cols[0])/divCoef;
|
||||
usedColors += cols[j];
|
||||
}
|
||||
|
@ -369,17 +488,20 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
|
|||
// octree table for separate alpha range with 1-based index (0 is fully transparent: no color)
|
||||
octree<rgb> trees[MAX_OCTREE_LEVELS];
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
|
||||
{
|
||||
trees[j].setMaxColors(cols[j]);
|
||||
}
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
typename T2::pixel_type const * row = image.getRow(y);
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
unsigned val = row[x];
|
||||
|
||||
// insert to proper tree based on alpha range
|
||||
for(unsigned j=TRANSPARENCY_LEVELS-1; j>0; j--){
|
||||
if (cols[j]>0 && U2ALPHA(val)>=limits[j]) {
|
||||
for(unsigned j=TRANSPARENCY_LEVELS-1; j>0; j--)
|
||||
{
|
||||
if (cols[j]>0 && U2ALPHA(val)>=limits[j])
|
||||
{
|
||||
trees[j].insert(mapnik::rgb(U2RED(val), U2GREEN(val), U2BLUE(val)));
|
||||
break;
|
||||
}
|
||||
|
@ -390,11 +512,16 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
|
|||
std::vector<rgb> palette;
|
||||
palette.reserve(max_colors);
|
||||
if (cols[0])
|
||||
{
|
||||
palette.push_back(rgb(0,0,0));
|
||||
}
|
||||
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++) {
|
||||
if (cols[j]>0) {
|
||||
if (leftovers>0) {
|
||||
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
|
||||
{
|
||||
if (cols[j]>0)
|
||||
{
|
||||
if (leftovers>0)
|
||||
{
|
||||
cols[j] += leftovers;
|
||||
trees[j].setMaxColors(cols[j]);
|
||||
leftovers = 0;
|
||||
|
@ -405,7 +532,8 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
|
|||
assert(pal.size() <= max_colors);
|
||||
leftovers = cols[j]-pal.size();
|
||||
cols[j] = pal.size();
|
||||
for(unsigned i=0; i<pal.size(); i++){
|
||||
for(unsigned i=0; i<pal.size(); i++)
|
||||
{
|
||||
palette.push_back(pal[i]);
|
||||
}
|
||||
assert(palette.size() <= 256);
|
||||
|
@ -416,14 +544,16 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
|
|||
std::vector<unsigned> alphaTable;
|
||||
//alphaTable.resize(palette.size());//allow semitransparency also in almost opaque range
|
||||
if (trans_mode != 0)
|
||||
{
|
||||
alphaTable.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
|
||||
}
|
||||
|
||||
if (palette.size() > 16 )
|
||||
{
|
||||
// >16 && <=256 colors -> write 8-bit color depth
|
||||
image_data_8 reduced_image(width,height);
|
||||
reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
|
||||
save_as_png(file,palette,reduced_image,width,height,8,compression,strategy,alphaTable);
|
||||
save_as_png(file,palette,reduced_image,width,height,8,compression,strategy,alphaTable,use_miniz);
|
||||
}
|
||||
else if (palette.size() == 1)
|
||||
{
|
||||
|
@ -432,11 +562,12 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
|
|||
unsigned image_height = height;
|
||||
image_data_8 reduced_image(image_width,image_height);
|
||||
reduce_1(image,reduced_image,trees, limits, alphaTable);
|
||||
if (meanAlpha<255 && cols[0]==0) {
|
||||
if (meanAlpha<255 && cols[0]==0)
|
||||
{
|
||||
alphaTable.resize(1);
|
||||
alphaTable[0] = meanAlpha;
|
||||
}
|
||||
save_as_png(file,palette,reduced_image,width,height,1,compression,strategy,alphaTable);
|
||||
save_as_png(file,palette,reduced_image,width,height,1,compression,strategy,alphaTable,use_miniz);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -445,15 +576,20 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
|
|||
unsigned image_height = height;
|
||||
image_data_8 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,compression,strategy,alphaTable);
|
||||
save_as_png(file,palette,reduced_image,width,height,4,compression,strategy,alphaTable,use_miniz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
|
||||
std::vector<mapnik::rgb> const& palette, std::vector<unsigned> const& alphaTable,
|
||||
int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY)
|
||||
void save_as_png8(T1 & file,
|
||||
T2 const& image,
|
||||
T3 const & tree,
|
||||
std::vector<mapnik::rgb> const& palette,
|
||||
std::vector<unsigned> const& alphaTable,
|
||||
int compression = Z_DEFAULT_COMPRESSION,
|
||||
int strategy = Z_DEFAULT_STRATEGY,
|
||||
bool use_miniz = false)
|
||||
{
|
||||
unsigned width = image.width();
|
||||
unsigned height = image.height();
|
||||
|
@ -462,18 +598,16 @@ void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
|
|||
{
|
||||
// >16 && <=256 colors -> write 8-bit color depth
|
||||
image_data_8 reduced_image(width, height);
|
||||
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
mapnik::image_data_32::pixel_type const * row = image.getRow(y);
|
||||
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y);
|
||||
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
row_out[x] = tree.quantize(row[x]);
|
||||
}
|
||||
}
|
||||
save_as_png(file, palette, reduced_image, width, height, 8, compression, strategy, alphaTable);
|
||||
save_as_png(file, palette, reduced_image, width, height, 8, compression, strategy, alphaTable, use_miniz);
|
||||
}
|
||||
else if (palette.size() == 1)
|
||||
{
|
||||
|
@ -482,7 +616,7 @@ void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
|
|||
unsigned image_height = height;
|
||||
image_data_8 reduced_image(image_width, image_height);
|
||||
reduced_image.set(0);
|
||||
save_as_png(file, palette, reduced_image, width, height, 1, compression, strategy, alphaTable);
|
||||
save_as_png(file, palette, reduced_image, width, height, 1, compression, strategy, alphaTable, use_miniz);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -495,23 +629,30 @@ void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
|
|||
mapnik::image_data_32::pixel_type const * row = image.getRow(y);
|
||||
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y);
|
||||
byte index = 0;
|
||||
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
|
||||
index = tree.quantize(row[x]);
|
||||
if (x%2 == 0) index = index<<4;
|
||||
if (x%2 == 0)
|
||||
{
|
||||
index = index<<4;
|
||||
}
|
||||
row_out[x>>1] |= index;
|
||||
}
|
||||
}
|
||||
save_as_png(file, palette, reduced_image, width, height, 4, compression, strategy, alphaTable);
|
||||
save_as_png(file, palette, reduced_image, width, height, 4, compression, strategy, alphaTable, use_miniz);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1,typename T2>
|
||||
void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
|
||||
int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY,
|
||||
int trans_mode = -1, double gamma = 2.0)
|
||||
void save_as_png8_hex(T1 & file,
|
||||
T2 const& image,
|
||||
int colors = 256,
|
||||
int compression = Z_DEFAULT_COMPRESSION,
|
||||
int strategy = Z_DEFAULT_STRATEGY,
|
||||
int trans_mode = -1,
|
||||
double gamma = 2.0,
|
||||
bool use_miniz = false)
|
||||
{
|
||||
unsigned width = image.width();
|
||||
unsigned height = image.height();
|
||||
|
@ -519,9 +660,13 @@ void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
|
|||
// structure for color quantization
|
||||
hextree<mapnik::rgba> tree(colors);
|
||||
if (trans_mode >= 0)
|
||||
{
|
||||
tree.setTransMode(trans_mode);
|
||||
}
|
||||
if (gamma > 0)
|
||||
{
|
||||
tree.setGamma(gamma);
|
||||
}
|
||||
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
|
@ -537,7 +682,6 @@ void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
|
|||
std::vector<mapnik::rgba> pal;
|
||||
tree.create_palette(pal);
|
||||
assert(int(pal.size()) <= colors);
|
||||
|
||||
std::vector<mapnik::rgb> palette;
|
||||
std::vector<unsigned> alphaTable;
|
||||
for(unsigned i=0; i<pal.size(); i++)
|
||||
|
@ -546,14 +690,18 @@ void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
|
|||
alphaTable.push_back(pal[i].a);
|
||||
}
|
||||
|
||||
save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alphaTable, compression, strategy);
|
||||
save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alphaTable, compression, strategy, use_miniz);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void save_as_png8_pal(T1 & file, T2 const& image, rgba_palette const& pal,
|
||||
int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY)
|
||||
void save_as_png8_pal(T1 & file,
|
||||
T2 const& image,
|
||||
rgba_palette const& pal,
|
||||
int compression = Z_DEFAULT_COMPRESSION,
|
||||
int strategy = Z_DEFAULT_STRATEGY,
|
||||
bool use_miniz = false)
|
||||
{
|
||||
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alphaTable(), compression, strategy);
|
||||
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alphaTable(), compression, strategy, use_miniz);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <map>
|
||||
#include <deque>
|
||||
#include <ctime>
|
||||
#include <cassert>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
@ -71,8 +72,8 @@ class Pool : private boost::noncopyable
|
|||
typedef std::deque<HolderType> ContType;
|
||||
|
||||
Creator<T> creator_;
|
||||
const unsigned initialSize_;
|
||||
const unsigned maxSize_;
|
||||
unsigned initialSize_;
|
||||
unsigned maxSize_;
|
||||
ContType usedPool_;
|
||||
ContType unusedPool_;
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
|
@ -80,7 +81,7 @@ class Pool : private boost::noncopyable
|
|||
#endif
|
||||
public:
|
||||
|
||||
Pool(const Creator<T>& creator,unsigned initialSize=1, unsigned maxSize=10)
|
||||
Pool(const Creator<T>& creator,unsigned initialSize, unsigned maxSize)
|
||||
:creator_(creator),
|
||||
initialSize_(initialSize),
|
||||
maxSize_(maxSize)
|
||||
|
@ -107,7 +108,7 @@ public:
|
|||
{
|
||||
usedPool_.push_back(*itr);
|
||||
unusedPool_.erase(itr);
|
||||
return usedPool_[usedPool_.size()-1];
|
||||
return usedPool_.back();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -116,6 +117,7 @@ public:
|
|||
itr=unusedPool_.erase(itr);
|
||||
}
|
||||
}
|
||||
// all connection have been taken, check if we allowed to grow pool
|
||||
if (usedPool_.size() < maxSize_)
|
||||
{
|
||||
HolderType conn(creator_());
|
||||
|
@ -159,6 +161,54 @@ public:
|
|||
std::pair<unsigned,unsigned> size(unusedPool_.size(),usedPool_.size());
|
||||
return size;
|
||||
}
|
||||
|
||||
unsigned max_size() const
|
||||
{
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
mutex::scoped_lock lock(mutex_);
|
||||
#endif
|
||||
return maxSize_;
|
||||
}
|
||||
|
||||
void set_max_size(unsigned size)
|
||||
{
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
mutex::scoped_lock lock(mutex_);
|
||||
#endif
|
||||
maxSize_ = std::max(maxSize_,size);
|
||||
}
|
||||
|
||||
unsigned initial_size() const
|
||||
{
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
mutex::scoped_lock lock(mutex_);
|
||||
#endif
|
||||
return initialSize_;
|
||||
}
|
||||
|
||||
void set_initial_size(unsigned size)
|
||||
{
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
mutex::scoped_lock lock(mutex_);
|
||||
#endif
|
||||
if (size > initialSize_)
|
||||
{
|
||||
initialSize_ = size;
|
||||
unsigned total_size = usedPool_.size() + unusedPool_.size();
|
||||
// ensure we don't have ghost obj's in the pool.
|
||||
if (total_size < initialSize_)
|
||||
{
|
||||
unsigned grow_size = initialSize_ - total_size ;
|
||||
|
||||
for (unsigned i=0; i < grow_size; ++i)
|
||||
{
|
||||
HolderType conn(creator_());
|
||||
if (conn->isOK())
|
||||
unusedPool_.push_back(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -27,8 +27,9 @@
|
|||
#include <mapnik/ctrans.hpp>
|
||||
#include <mapnik/color.hpp>
|
||||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/svg/svg_output_grammars.hpp>
|
||||
#include <mapnik/svg/svg_output_attributes.hpp>
|
||||
#include <mapnik/util/geometry_svg_generator.hpp>
|
||||
#include <mapnik/svg/output/svg_output_grammars.hpp>
|
||||
#include <mapnik/svg/output/svg_output_attributes.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/utility.hpp>
|
||||
|
@ -44,11 +45,8 @@ namespace mapnik { namespace svg {
|
|||
template <typename OutputIterator>
|
||||
class svg_generator : private boost::noncopyable
|
||||
{
|
||||
typedef coord_transform<CoordTransform, geometry_type> path_type;
|
||||
|
||||
typedef svg::svg_root_attributes_grammar<OutputIterator> root_attributes_grammar;
|
||||
typedef svg::svg_rect_attributes_grammar<OutputIterator> rect_attributes_grammar;
|
||||
typedef svg::svg_path_data_grammar<OutputIterator, path_type> path_data_grammar;
|
||||
typedef svg::svg_path_attributes_grammar<OutputIterator> path_attributes_grammar;
|
||||
typedef svg::svg_path_dash_array_grammar<OutputIterator> path_dash_array_grammar;
|
||||
|
||||
|
@ -60,7 +58,16 @@ namespace mapnik { namespace svg {
|
|||
void generate_opening_root(root_output_attributes const& root_attributes);
|
||||
void generate_closing_root();
|
||||
void generate_rect(rect_output_attributes const& rect_attributes);
|
||||
void generate_path(path_type const& path, path_output_attributes const& path_attributes);
|
||||
template <typename PathType>
|
||||
void generate_path(PathType const& path, path_output_attributes const& path_attributes)
|
||||
{
|
||||
util::svg_generator<OutputIterator,PathType> svg_path_grammer;
|
||||
karma::generate(output_iterator_, lit("<path ") << svg_path_grammer, path);
|
||||
path_attributes_grammar attributes_grammar;
|
||||
path_dash_array_grammar dash_array_grammar;
|
||||
karma::generate(output_iterator_, lit(" ") << dash_array_grammar, path_attributes.stroke_dasharray());
|
||||
karma::generate(output_iterator_, lit(" ") << attributes_grammar << lit("/>\n"), path_attributes);
|
||||
}
|
||||
|
||||
private:
|
||||
OutputIterator& output_iterator_;
|
||||
|
|
|
@ -87,84 +87,11 @@ BOOST_FUSION_ADAPT_STRUCT(
|
|||
(std::string, svg_namespace_url_)
|
||||
)
|
||||
|
||||
/*!
|
||||
* mapnik::geometry_type is adapted to conform to the concepts
|
||||
* required by Karma to be recognized as a container of
|
||||
* attributes for output generation.
|
||||
*/
|
||||
namespace boost { namespace spirit { namespace traits {
|
||||
|
||||
typedef mapnik::coord_transform<mapnik::CoordTransform, mapnik::geometry_type> path_type;
|
||||
|
||||
template <>
|
||||
struct is_container<path_type const>
|
||||
: mpl::true_ {};
|
||||
|
||||
template <>
|
||||
struct container_iterator<path_type const>
|
||||
{
|
||||
typedef mapnik::svg::path_iterator_type type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct begin_container<path_type const>
|
||||
{
|
||||
static mapnik::svg::path_iterator_type
|
||||
call(path_type const& path)
|
||||
{
|
||||
return mapnik::svg::path_iterator_type(0, path);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct end_container<path_type const>
|
||||
{
|
||||
static mapnik::svg::path_iterator_type
|
||||
call(path_type const& path)
|
||||
{
|
||||
return mapnik::svg::path_iterator_type(path);
|
||||
}
|
||||
};
|
||||
}}}
|
||||
|
||||
namespace mapnik { namespace svg {
|
||||
|
||||
using namespace boost::spirit;
|
||||
using namespace boost::phoenix;
|
||||
|
||||
template <typename OutputIterator, typename PathType>
|
||||
struct svg_path_data_grammar : karma::grammar<OutputIterator, PathType&()>
|
||||
{
|
||||
typedef path_iterator_type::value_type vertex_type;
|
||||
|
||||
explicit svg_path_data_grammar(PathType const& path_type)
|
||||
: svg_path_data_grammar::base_type(svg_path),
|
||||
path_type_(path_type)
|
||||
{
|
||||
using karma::int_;
|
||||
using karma::double_;
|
||||
using repository::confix;
|
||||
|
||||
svg_path =
|
||||
lit("d=")
|
||||
<< confix('"', '"')[
|
||||
-(path_vertex % lit(' '))];
|
||||
|
||||
path_vertex =
|
||||
path_vertex_command
|
||||
<< double_
|
||||
<< lit(' ')
|
||||
<< double_;
|
||||
|
||||
path_vertex_command = &int_(1) << lit('M') | lit('L');
|
||||
}
|
||||
|
||||
karma::rule<OutputIterator, PathType&()> svg_path;
|
||||
karma::rule<OutputIterator, vertex_type()> path_vertex;
|
||||
karma::rule<OutputIterator, int()> path_vertex_command;
|
||||
|
||||
PathType const& path_type_;
|
||||
};
|
||||
|
||||
template <typename OutputIterator>
|
||||
struct svg_path_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg::path_output_attributes()>
|
||||
|
|
|
@ -62,7 +62,7 @@ class path_iterator
|
|||
public:
|
||||
typedef Value value_type;
|
||||
typedef Container container_type;
|
||||
typedef typename Container::value_type value_component_type;
|
||||
//typedef typename Container::value_type value_component_type;
|
||||
|
||||
/*!
|
||||
* @brief Constructor that initializes the reference to the current element to null.
|
||||
|
@ -119,8 +119,8 @@ private:
|
|||
void increment()
|
||||
{
|
||||
// variables used to extract vertex components.
|
||||
geometry_type::value_type x;
|
||||
geometry_type::value_type y;
|
||||
geometry_type::coord_type x;
|
||||
geometry_type::coord_type y;
|
||||
|
||||
// extract next vertex components.
|
||||
unsigned cmd = path_.vertex(&x, &y);
|
||||
|
@ -173,8 +173,8 @@ private:
|
|||
* The Value type is a boost::tuple that holds 5 elements, the command and the x and y coordinate.
|
||||
* Each coordinate is stored twice to match the needs of the grammar.
|
||||
*/
|
||||
typedef path_iterator<boost::tuple<unsigned, geometry_type::value_type, geometry_type::value_type>,
|
||||
coord_transform<CoordTransform, geometry_type> > path_iterator_type;
|
||||
//typedef path_iterator<boost::tuple<unsigned, geometry_type::coord_type, geometry_type::value_type>,
|
||||
// coord_transform<CoordTransform, geometry_type> > path_iterator_type;
|
||||
|
||||
}}
|
||||
|
||||
|
|
|
@ -42,54 +42,60 @@ class MAPNIK_DECL svg_renderer : public feature_style_processor<svg_renderer<Out
|
|||
private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef svg_renderer<OutputIterator> processor_impl_type;
|
||||
svg_renderer(Map const& m, OutputIterator& output_iterator, unsigned offset_x=0, unsigned offset_y=0);
|
||||
~svg_renderer();
|
||||
|
||||
void start_map_processing(Map const& map);
|
||||
void end_map_processing(Map const& map);
|
||||
void start_layer_processing(layer const& lay);
|
||||
void start_layer_processing(layer const& lay, box2d<double> const& query_extent);
|
||||
void end_layer_processing(layer const& lay);
|
||||
void start_style_processing(feature_type_style const& st) {}
|
||||
void end_style_processing(feature_type_style const& st) {}
|
||||
|
||||
/*!
|
||||
* @brief Overloads that process each kind of symbolizer individually.
|
||||
*/
|
||||
void process(point_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(line_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(line_pattern_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(polygon_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(polygon_pattern_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(raster_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(shield_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(building_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(markers_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
void process(debug_symbolizer const& sym,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans) {}
|
||||
|
||||
/*!
|
||||
* @brief Overload that process the whole set of symbolizers of a rule.
|
||||
* @return true, meaning that this renderer can process multiple symbolizers.
|
||||
*/
|
||||
bool process(rule::symbolizers const& syms,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
|
||||
void painted(bool painted)
|
||||
|
@ -114,6 +120,7 @@ private:
|
|||
CoordTransform t_;
|
||||
svg::svg_generator<OutputIterator> generator_;
|
||||
svg::path_output_attributes path_attributes_;
|
||||
box2d<double> query_extent_;
|
||||
bool painted_;
|
||||
|
||||
/*!
|
||||
|
@ -125,7 +132,7 @@ private:
|
|||
struct symbol_dispatch : public boost::static_visitor<>
|
||||
{
|
||||
symbol_dispatch(svg_renderer<OutputIterator>& processor,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
: processor_(processor),
|
||||
feature_(feature),
|
||||
|
@ -138,7 +145,7 @@ private:
|
|||
}
|
||||
|
||||
svg_renderer<OutputIterator>& processor_;
|
||||
Feature const& feature_;
|
||||
mapnik::feature_impl & feature_;
|
||||
proj_transform const& prj_trans_;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
|
||||
// mapnik
|
||||
#include <mapnik/global.hpp>
|
||||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/geometry.hpp> // for container stuff
|
||||
#include <mapnik/ctrans.hpp> // for container stuff
|
||||
#include <mapnik/util/path_iterator.hpp>
|
||||
#include <mapnik/util/container_adapter.hpp>
|
||||
|
||||
|
@ -38,35 +39,84 @@
|
|||
#include <boost/spirit/include/phoenix_function.hpp>
|
||||
#include <boost/spirit/home/phoenix/statement/if.hpp>
|
||||
#include <boost/fusion/include/boost_tuple.hpp>
|
||||
#include <boost/type_traits/remove_pointer.hpp>
|
||||
|
||||
//#define BOOST_SPIRIT_USE_PHOENIX_V3 1
|
||||
|
||||
/*!
|
||||
* adapted to conform to the concepts
|
||||
* required by Karma to be recognized as a container of
|
||||
* attributes for output generation.
|
||||
*/
|
||||
namespace boost { namespace spirit { namespace traits {
|
||||
|
||||
// TODO - this needs to be made generic to any path type
|
||||
typedef mapnik::coord_transform<mapnik::CoordTransform, mapnik::geometry_type> path_type;
|
||||
|
||||
template <>
|
||||
struct is_container<path_type const> : mpl::true_ {} ;
|
||||
|
||||
template <>
|
||||
struct container_iterator<path_type const>
|
||||
{
|
||||
typedef mapnik::util::path_iterator<path_type> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct begin_container<path_type const>
|
||||
{
|
||||
static mapnik::util::path_iterator<path_type>
|
||||
call (path_type const& g)
|
||||
{
|
||||
return mapnik::util::path_iterator<path_type>(g);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct end_container<path_type const>
|
||||
{
|
||||
static mapnik::util::path_iterator<path_type>
|
||||
call (path_type const& g)
|
||||
{
|
||||
return mapnik::util::path_iterator<path_type>();
|
||||
}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
namespace mapnik { namespace util {
|
||||
|
||||
namespace karma = boost::spirit::karma;
|
||||
namespace phoenix = boost::phoenix;
|
||||
|
||||
namespace svg_detail {
|
||||
|
||||
template <typename Geometry>
|
||||
struct get_type
|
||||
{
|
||||
template <typename T>
|
||||
struct result { typedef int type; };
|
||||
|
||||
int operator() (geometry_type const& geom) const
|
||||
int operator() (Geometry const& geom) const
|
||||
{
|
||||
return (int)geom.type();
|
||||
return static_cast<int>(geom.type());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct get_first
|
||||
{
|
||||
template <typename T>
|
||||
struct result { typedef geometry_type::value_type const type; };
|
||||
typedef T geometry_type;
|
||||
|
||||
geometry_type::value_type const operator() (geometry_type const& geom) const
|
||||
template <typename U>
|
||||
struct result { typedef typename geometry_type::value_type const type; };
|
||||
|
||||
typename geometry_type::value_type const operator() (geometry_type const& geom) const
|
||||
{
|
||||
geometry_type::value_type coord;
|
||||
boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord));
|
||||
typename geometry_type::value_type coord;
|
||||
geom.rewind(0);
|
||||
boost::get<0>(coord) = geom.vertex(&boost::get<1>(coord),&boost::get<2>(coord));
|
||||
return coord;
|
||||
}
|
||||
};
|
||||
|
@ -80,11 +130,14 @@ namespace mapnik { namespace util {
|
|||
};
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
template <typename OutputIterator, typename Geometry>
|
||||
struct svg_generator :
|
||||
karma::grammar<OutputIterator, geometry_type const& ()>
|
||||
karma::grammar<OutputIterator, Geometry const& ()>
|
||||
{
|
||||
|
||||
typedef Geometry geometry_type;
|
||||
typedef typename boost::remove_pointer<typename geometry_type::value_type>::type coord_type;
|
||||
|
||||
svg_generator()
|
||||
: svg_generator::base_type(svg)
|
||||
{
|
||||
|
@ -102,22 +155,22 @@ namespace mapnik { namespace util {
|
|||
;
|
||||
|
||||
svg_point = &uint_
|
||||
<< lit("cx=\"") << coord_type
|
||||
<< lit("\" cy=\"") << coord_type
|
||||
<< lit("cx=\"") << coordinate
|
||||
<< lit("\" cy=\"") << coordinate
|
||||
<< lit('\"')
|
||||
;
|
||||
|
||||
linestring = &uint_(mapnik::LineString)[_1 = _type(_val)]
|
||||
<< svg_path
|
||||
<< svg_path << lit('\"')
|
||||
;
|
||||
|
||||
polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)]
|
||||
<< svg_path
|
||||
<< svg_path << lit('\"')
|
||||
;
|
||||
|
||||
svg_path %= ((&uint_(mapnik::SEG_MOVETO) << lit('M')
|
||||
svg_path %= ((&uint_(mapnik::SEG_MOVETO) << lit("d=\"") << lit('M')
|
||||
| &uint_(mapnik::SEG_LINETO) [_a +=1] << karma::string [if_(_a == 1) [_1 = "L" ] ])
|
||||
<< lit(' ') << coord_type << lit(' ') << coord_type) % lit(' ')
|
||||
<< lit(' ') << coordinate << lit(' ') << coordinate) % lit(' ')
|
||||
;
|
||||
|
||||
|
||||
|
@ -129,14 +182,14 @@ namespace mapnik { namespace util {
|
|||
karma::rule<OutputIterator, geometry_type const& ()> linestring;
|
||||
karma::rule<OutputIterator, geometry_type const& ()> polygon;
|
||||
|
||||
karma::rule<OutputIterator, geometry_type::value_type ()> svg_point;
|
||||
karma::rule<OutputIterator, coord_type ()> svg_point;
|
||||
karma::rule<OutputIterator, karma::locals<unsigned>, geometry_type const& ()> svg_path;
|
||||
|
||||
// phoenix functions
|
||||
phoenix::function<svg_detail::get_type > _type;
|
||||
phoenix::function<svg_detail::get_first> _first;
|
||||
phoenix::function<svg_detail::get_type<geometry_type> > _type;
|
||||
phoenix::function<svg_detail::get_first<geometry_type> > _first;
|
||||
//
|
||||
karma::real_generator<double, svg_detail::coordinate_policy<double> > coord_type;
|
||||
karma::real_generator<double, svg_detail::coordinate_policy<double> > coordinate;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ bool to_svg(std::string & svg, mapnik::geometry_type const& geom)
|
|||
{
|
||||
typedef std::back_insert_iterator<std::string> sink_type;
|
||||
sink_type sink(svg);
|
||||
svg_generator<sink_type> generator;
|
||||
svg_generator<sink_type, mapnik::geometry_type> generator;
|
||||
bool result = karma::generate(sink, generator, geom);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -365,6 +365,16 @@ struct vertex_converter : private boost::noncopyable
|
|||
disp_.vec_[index]=1;
|
||||
}
|
||||
|
||||
template <typename Conv>
|
||||
void unset()
|
||||
{
|
||||
typedef typename boost::mpl::find<conv_types,Conv>::type iter;
|
||||
typedef typename boost::mpl::end<conv_types>::type end;
|
||||
std::size_t index = boost::mpl::distance<iter,end>::value - 1;
|
||||
if (index < disp_.vec_.size())
|
||||
disp_.vec_[index]=0;
|
||||
}
|
||||
|
||||
|
||||
detail::dispatcher<args_type,conv_types> disp_;
|
||||
};
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "ogr_datasource.hpp"
|
||||
#include "ogr_featureset.hpp"
|
||||
#include "ogr_index_featureset.hpp"
|
||||
#include "ogr_feature_ptr.hpp"
|
||||
|
||||
#include <gdal_version.h>
|
||||
|
||||
|
@ -394,10 +393,10 @@ boost::optional<mapnik::datasource::geometry_t> ogr_datasource::get_geometry_typ
|
|||
// only new either reset of setNext
|
||||
//layer->ResetReading();
|
||||
layer->SetNextByIndex(0);
|
||||
ogr_feature_ptr feat(layer->GetNextFeature());
|
||||
if ((*feat) != NULL)
|
||||
OGRFeature *poFeature;
|
||||
while ((poFeature = layer->GetNextFeature()) != NULL)
|
||||
{
|
||||
OGRGeometry* geom = (*feat)->GetGeometryRef();
|
||||
OGRGeometry* geom = poFeature->GetGeometryRef();
|
||||
if (geom && ! geom->IsEmpty())
|
||||
{
|
||||
switch (wkbFlatten(geom->getGeometryType()))
|
||||
|
@ -422,6 +421,8 @@ boost::optional<mapnik::datasource::geometry_t> ogr_datasource::get_geometry_typ
|
|||
break;
|
||||
}
|
||||
}
|
||||
OGRFeature::DestroyFeature( poFeature );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2011 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 OGR_FEATURE_PTR_HPP
|
||||
#define OGR_FEATURE_PTR_HPP
|
||||
|
||||
// ogr
|
||||
#include <ogrsf_frmts.h>
|
||||
|
||||
class ogr_feature_ptr
|
||||
{
|
||||
public:
|
||||
ogr_feature_ptr(OGRFeature* const feat)
|
||||
: feat_(feat)
|
||||
{
|
||||
}
|
||||
|
||||
~ogr_feature_ptr()
|
||||
{
|
||||
if (feat_ != NULL)
|
||||
{
|
||||
OGRFeature::DestroyFeature(feat_);
|
||||
}
|
||||
}
|
||||
|
||||
OGRFeature* operator*()
|
||||
{
|
||||
return feat_;
|
||||
}
|
||||
|
||||
private:
|
||||
OGRFeature* feat_;
|
||||
};
|
||||
|
||||
#endif // OGR_FEATURE_PTR_HPP
|
|
@ -35,7 +35,6 @@
|
|||
// ogr
|
||||
#include "ogr_featureset.hpp"
|
||||
#include "ogr_converter.hpp"
|
||||
#include "ogr_feature_ptr.hpp"
|
||||
|
||||
using mapnik::query;
|
||||
using mapnik::box2d;
|
||||
|
@ -84,23 +83,24 @@ ogr_featureset::~ogr_featureset()
|
|||
|
||||
feature_ptr ogr_featureset::next()
|
||||
{
|
||||
ogr_feature_ptr feat (layer_.GetNextFeature());
|
||||
|
||||
while ((*feat) != NULL)
|
||||
OGRFeature *poFeature;
|
||||
while ((poFeature = layer_.GetNextFeature()) != NULL)
|
||||
{
|
||||
// ogr feature ids start at 0, so add one to stay
|
||||
// consistent with other mapnik datasources that start at 1
|
||||
const int feature_id = ((*feat)->GetFID() + 1);
|
||||
const int feature_id = (poFeature->GetFID() + 1);
|
||||
feature_ptr feature(feature_factory::create(ctx_,feature_id));
|
||||
|
||||
OGRGeometry* geom = (*feat)->GetGeometryRef();
|
||||
OGRGeometry* geom = poFeature->GetGeometryRef();
|
||||
if (geom && ! geom->IsEmpty())
|
||||
{
|
||||
ogr_converter::convert_geometry(geom, feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(ogr) << "ogr_featureset: Feature with null geometry=" << (*feat)->GetFID();
|
||||
MAPNIK_LOG_DEBUG(ogr) << "ogr_featureset: Feature with null geometry="
|
||||
<< poFeature->GetFID();
|
||||
OGRFeature::DestroyFeature( poFeature );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -117,20 +117,20 @@ feature_ptr ogr_featureset::next()
|
|||
{
|
||||
case OFTInteger:
|
||||
{
|
||||
feature->put( fld_name, (*feat)->GetFieldAsInteger(i));
|
||||
feature->put( fld_name, poFeature->GetFieldAsInteger(i));
|
||||
break;
|
||||
}
|
||||
|
||||
case OFTReal:
|
||||
{
|
||||
feature->put( fld_name, (*feat)->GetFieldAsDouble(i));
|
||||
feature->put( fld_name, poFeature->GetFieldAsDouble(i));
|
||||
break;
|
||||
}
|
||||
|
||||
case OFTString:
|
||||
case OFTWideString: // deprecated !
|
||||
{
|
||||
UnicodeString ustr = tr_->transcode((*feat)->GetFieldAsString(i));
|
||||
UnicodeString ustr = tr_->transcode(poFeature->GetFieldAsString(i));
|
||||
feature->put( fld_name, ustr);
|
||||
break;
|
||||
}
|
||||
|
@ -166,6 +166,7 @@ feature_ptr ogr_featureset::next()
|
|||
}
|
||||
}
|
||||
}
|
||||
OGRFeature::DestroyFeature( poFeature );
|
||||
return feature;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include "ogr_index_featureset.hpp"
|
||||
#include "ogr_converter.hpp"
|
||||
#include "ogr_index.hpp"
|
||||
#include "ogr_feature_ptr.hpp"
|
||||
|
||||
using mapnik::query;
|
||||
using mapnik::box2d;
|
||||
|
@ -92,24 +91,27 @@ feature_ptr ogr_index_featureset<filterT>::next()
|
|||
int pos = *itr_++;
|
||||
layer_.SetNextByIndex (pos);
|
||||
|
||||
ogr_feature_ptr feat (layer_.GetNextFeature());
|
||||
if ((*feat) == NULL)
|
||||
OGRFeature *poFeature = layer_.GetNextFeature();
|
||||
if (poFeature == NULL)
|
||||
{
|
||||
continue;
|
||||
return feature_ptr();
|
||||
}
|
||||
|
||||
// ogr feature ids start at 0, so add one to stay
|
||||
// consistent with other mapnik datasources that start at 1
|
||||
int feature_id = ((*feat)->GetFID() + 1);
|
||||
int feature_id = (poFeature->GetFID() + 1);
|
||||
feature_ptr feature(feature_factory::create(ctx_,feature_id));
|
||||
|
||||
OGRGeometry* geom=(*feat)->GetGeometryRef();
|
||||
OGRGeometry* geom=poFeature->GetGeometryRef();
|
||||
if (geom && !geom->IsEmpty())
|
||||
{
|
||||
ogr_converter::convert_geometry (geom, feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(ogr) << "ogr_index_featureset: Feature with null geometry=" << (*feat)->GetFID();
|
||||
MAPNIK_LOG_DEBUG(ogr) << "ogr_index_featureset: Feature with null geometry="
|
||||
<< poFeature->GetFID();
|
||||
OGRFeature::DestroyFeature( poFeature );
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -124,20 +126,20 @@ feature_ptr ogr_index_featureset<filterT>::next()
|
|||
{
|
||||
case OFTInteger:
|
||||
{
|
||||
feature->put(fld_name,(*feat)->GetFieldAsInteger (i));
|
||||
feature->put(fld_name,poFeature->GetFieldAsInteger (i));
|
||||
break;
|
||||
}
|
||||
|
||||
case OFTReal:
|
||||
{
|
||||
feature->put(fld_name,(*feat)->GetFieldAsDouble (i));
|
||||
feature->put(fld_name,poFeature->GetFieldAsDouble (i));
|
||||
break;
|
||||
}
|
||||
|
||||
case OFTString:
|
||||
case OFTWideString: // deprecated !
|
||||
{
|
||||
UnicodeString ustr = tr_->transcode((*feat)->GetFieldAsString (i));
|
||||
UnicodeString ustr = tr_->transcode(poFeature->GetFieldAsString (i));
|
||||
feature->put(fld_name,ustr);
|
||||
break;
|
||||
}
|
||||
|
@ -167,6 +169,7 @@ feature_ptr ogr_index_featureset<filterT>::next()
|
|||
}
|
||||
}
|
||||
}
|
||||
OGRFeature::DestroyFeature( poFeature );
|
||||
return feature;
|
||||
}
|
||||
|
||||
|
|
|
@ -254,7 +254,7 @@ bool osm_way::is_polygon()
|
|||
for (unsigned int count = 0; count < ptypes.ptypes.size(); ++count)
|
||||
{
|
||||
if (keyvals.find(ptypes.ptypes[count].first) != keyvals.end() &&
|
||||
keyvals[ptypes.ptypes[count].first] == ptypes.ptypes[count].second)
|
||||
(ptypes.ptypes[count].second.empty() || keyvals[ptypes.ptypes[count].first] == ptypes.ptypes[count].second))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -49,13 +49,17 @@ public:
|
|||
|
||||
polygon_types()
|
||||
{
|
||||
ptypes.push_back(std::pair<std::string, std::string>("water", ""));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("aeroway", ""));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("building", ""));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("natural", "wood"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("natural", "water"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("natural", "heath"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("natural", "marsh"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("military", "danger_area"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("landuse","forest"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("landuse","industrial"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("landuse", "forest"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("landuse", "industrial"));
|
||||
ptypes.push_back(std::pair<std::string, std::string>("leisure", "park"));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ osm_featureset<filterT>::osm_featureset(const filterT& filter,
|
|||
: filter_(filter),
|
||||
query_ext_(),
|
||||
tr_(new transcoder(encoding)),
|
||||
feature_id_(1),
|
||||
dataset_ (dataset),
|
||||
attribute_names_ (attribute_names),
|
||||
ctx_(boost::make_shared<mapnik::context_type>())
|
||||
|
@ -62,8 +61,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_id_;
|
||||
feature = feature_factory::create(ctx_, cur_item->id);
|
||||
double lat = static_cast<osm_node*>(cur_item)->lat;
|
||||
double lon = static_cast<osm_node*>(cur_item)->lon;
|
||||
geometry_type* point = new geometry_type(mapnik::Point);
|
||||
|
@ -83,8 +81,7 @@ feature_ptr osm_featureset<filterT>::next()
|
|||
}
|
||||
|
||||
if (!cur_item) return feature_ptr();
|
||||
feature = feature_factory::create(ctx_, feature_id_);
|
||||
++feature_id_;
|
||||
feature = feature_factory::create(ctx_, cur_item->id);
|
||||
geometry_type* geom;
|
||||
if (static_cast<osm_way*>(cur_item)->is_polygon())
|
||||
{
|
||||
|
|
|
@ -61,7 +61,6 @@ private:
|
|||
std::vector<int> attr_ids_;
|
||||
mutable box2d<double> feature_ext_;
|
||||
mutable int total_geom_size;
|
||||
mutable int feature_id_;
|
||||
osm_dataset *dataset_;
|
||||
std::set<std::string> attribute_names_;
|
||||
mapnik::context_ptr ctx_;
|
||||
|
|
|
@ -66,16 +66,8 @@ void osmparser::startElement(xmlTextReaderPtr reader, const xmlChar *name)
|
|||
assert(xid);
|
||||
way->id = atol((char*)xid);
|
||||
cur_item = way;
|
||||
// Prevent ways with no name being assigned a name of "0"
|
||||
// Prevent ways with no name being assigned a name of "true"
|
||||
cur_item->keyvals["name"] = "";
|
||||
|
||||
// HACK: allows comparison with "" in the XML file. Otherwise it
|
||||
// doesn't work. Only do for the most crucial tags for Freemap's
|
||||
// purposes. TODO investigate why this is
|
||||
cur_item->keyvals["width"] = "";
|
||||
cur_item->keyvals["horse"] = "";
|
||||
cur_item->keyvals["foot"] = "";
|
||||
cur_item->keyvals["bicycle"] = "";
|
||||
xmlFree(xid);
|
||||
}
|
||||
else if (xmlStrEqual(name,BAD_CAST "nd"))
|
||||
|
|
|
@ -44,34 +44,24 @@ extern "C" {
|
|||
class Connection
|
||||
{
|
||||
public:
|
||||
Connection(std::string const& connection_str)
|
||||
Connection(std::string const& connection_str,boost::optional<std::string> const& password)
|
||||
: cursorId(0),
|
||||
closed_(false)
|
||||
{
|
||||
conn_ = PQconnectdb(connection_str.c_str());
|
||||
std::string connect_with_pass = connection_str;
|
||||
if (password && !password->empty())
|
||||
{
|
||||
connect_with_pass += " password=" + *password;
|
||||
}
|
||||
conn_ = PQconnectdb(connect_with_pass.c_str());
|
||||
if (PQstatus(conn_) != CONNECTION_OK)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "Postgis Plugin: ";
|
||||
if (conn_ )
|
||||
{
|
||||
std::string msg = PQerrorMessage(conn_);
|
||||
if (! msg.empty())
|
||||
{
|
||||
s << msg.substr(0, msg.size() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "unable to connect to postgres server";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "unable to connect to postgres server";
|
||||
}
|
||||
s << "\n" << connection_str;
|
||||
|
||||
throw mapnik::datasource_exception(s.str());
|
||||
std::string err_msg = "Postgis Plugin: ";
|
||||
err_msg += status();
|
||||
err_msg += "\nConnection string: '";
|
||||
err_msg += connection_str;
|
||||
err_msg += "'\n";
|
||||
throw mapnik::datasource_exception(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,34 +107,35 @@ public:
|
|||
|
||||
if (! result || (PQresultStatus(result) != PGRES_TUPLES_OK))
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "Postgis Plugin: PSQL error";
|
||||
if (conn_)
|
||||
{
|
||||
std::string msg = PQerrorMessage(conn_);
|
||||
if (! msg.empty())
|
||||
{
|
||||
s << ":\n" << msg.substr(0, msg.size() - 1);
|
||||
}
|
||||
|
||||
s << "\nFull sql was: '" << sql << "'\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "unable to connect to database";
|
||||
}
|
||||
|
||||
std::string err_msg = status();
|
||||
err_msg += "\nFull sql was: '";
|
||||
err_msg += sql;
|
||||
err_msg += "'\n";
|
||||
if (result)
|
||||
{
|
||||
PQclear(result);
|
||||
}
|
||||
|
||||
throw mapnik::datasource_exception(s.str());
|
||||
throw mapnik::datasource_exception(err_msg);
|
||||
}
|
||||
|
||||
return boost::make_shared<ResultSet>(result);
|
||||
}
|
||||
|
||||
std::string status() const
|
||||
{
|
||||
std::string status;
|
||||
if (conn_)
|
||||
{
|
||||
status = PQerrorMessage(conn_);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = "Uninitialized connection";
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
std::string client_encoding() const
|
||||
{
|
||||
return PQparameterStatus(conn_, "client_encoding");
|
||||
|
|
|
@ -33,10 +33,6 @@
|
|||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
#include <boost/thread/mutex.hpp>
|
||||
//using boost::mutex;
|
||||
#endif
|
||||
|
||||
// stl
|
||||
#include <string>
|
||||
|
@ -66,7 +62,7 @@ public:
|
|||
|
||||
T* operator()() const
|
||||
{
|
||||
return new T(connection_string());
|
||||
return new T(connection_string_safe(),pass_);
|
||||
}
|
||||
|
||||
inline std::string id() const
|
||||
|
@ -75,14 +71,20 @@ public:
|
|||
}
|
||||
|
||||
inline std::string connection_string() const
|
||||
{
|
||||
std::string connect_str = connection_string_safe();
|
||||
if (pass_ && !pass_->empty()) connect_str += " password=" + *pass_;
|
||||
return connect_str;
|
||||
}
|
||||
|
||||
inline std::string connection_string_safe() const
|
||||
{
|
||||
std::string connect_str;
|
||||
if (host_ && (*host_).size()) connect_str += "host=" + *host_;
|
||||
if (port_ && (*port_).size()) connect_str += " port=" + *port_;
|
||||
if (dbname_ && (*dbname_).size()) connect_str += " dbname=" + *dbname_;
|
||||
if (user_ && (*user_).size()) connect_str += " user=" + *user_;
|
||||
if (pass_ && (*pass_).size()) connect_str += " password=" + *pass_;
|
||||
if (connect_timeout_ && (*connect_timeout_).size())
|
||||
if (host_ && !host_->empty()) connect_str += "host=" + *host_;
|
||||
if (port_ && !port_->empty()) connect_str += " port=" + *port_;
|
||||
if (dbname_ && !dbname_->empty()) connect_str += " dbname=" + *dbname_;
|
||||
if (user_ && !user_->empty()) connect_str += " user=" + *user_;
|
||||
if (connect_timeout_ && !connect_timeout_->empty())
|
||||
connect_str +=" connect_timeout=" + *connect_timeout_;
|
||||
return connect_str;
|
||||
}
|
||||
|
@ -109,24 +111,25 @@ public:
|
|||
|
||||
bool registerPool(const ConnectionCreator<Connection>& creator,unsigned initialSize,unsigned maxSize)
|
||||
{
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
//mutex::scoped_lock lock(mutex_);
|
||||
#endif
|
||||
if (pools_.find(creator.id())==pools_.end())
|
||||
{
|
||||
return pools_.insert(std::make_pair(creator.id(),
|
||||
boost::make_shared<PoolType>(creator,initialSize,maxSize))).second;
|
||||
}
|
||||
ContType::const_iterator itr = pools_.find(creator.id());
|
||||
|
||||
if (itr != pools_.end())
|
||||
{
|
||||
itr->second->set_initial_size(initialSize);
|
||||
itr->second->set_max_size(maxSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return pools_.insert(
|
||||
std::make_pair(creator.id(),
|
||||
boost::make_shared<PoolType>(creator,initialSize,maxSize))).second;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
boost::shared_ptr<PoolType> getPool(std::string const& key)
|
||||
{
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
//mutex::scoped_lock lock(mutex_);
|
||||
#endif
|
||||
ContType::const_iterator itr=pools_.find(key);
|
||||
if (itr!=pools_.end())
|
||||
{
|
||||
|
@ -136,19 +139,6 @@ public:
|
|||
return emptyPool;
|
||||
}
|
||||
|
||||
HolderType get(std::string const& key)
|
||||
{
|
||||
#ifdef MAPNIK_THREADSAFE
|
||||
//mutex::scoped_lock lock(mutex_);
|
||||
#endif
|
||||
ContType::const_iterator itr=pools_.find(key);
|
||||
if (itr!=pools_.end())
|
||||
{
|
||||
boost::shared_ptr<PoolType> pool=itr->second;
|
||||
return pool->borrowObject();
|
||||
}
|
||||
return HolderType();
|
||||
}
|
||||
ConnectionManager() {}
|
||||
private:
|
||||
ConnectionManager(const ConnectionManager&);
|
||||
|
|
|
@ -68,22 +68,22 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind)
|
|||
srid_(*params_.get<int>("srid", 0)),
|
||||
extent_initialized_(false),
|
||||
simplify_geometries_(false),
|
||||
desc_(*params_.get<std::string>("type"), "utf-8"),
|
||||
creator_(params.get<std::string>("host"),
|
||||
params.get<std::string>("port"),
|
||||
params.get<std::string>("dbname"),
|
||||
params.get<std::string>("user"),
|
||||
params.get<std::string>("password"),
|
||||
params.get<std::string>("connect_timeout", "4")),
|
||||
bbox_token_("!bbox!"),
|
||||
scale_denom_token_("!scale_denominator!"),
|
||||
pixel_width_token_("!pixel_width!"),
|
||||
pixel_height_token_("!pixel_height!"),
|
||||
persist_connection_(*params_.get<mapnik::boolean>("persist_connection", true)),
|
||||
extent_from_subquery_(*params_.get<mapnik::boolean>("extent_from_subquery", false)),
|
||||
// params below are for testing purposes only (will likely be removed at any time)
|
||||
intersect_min_scale_(*params_.get<int>("intersect_min_scale", 0)),
|
||||
intersect_max_scale_(*params_.get<int>("intersect_max_scale", 0))
|
||||
desc_(*params_.get<std::string>("type"), "utf-8"),
|
||||
creator_(params.get<std::string>("host"),
|
||||
params.get<std::string>("port"),
|
||||
params.get<std::string>("dbname"),
|
||||
params.get<std::string>("user"),
|
||||
params.get<std::string>("password"),
|
||||
params.get<std::string>("connect_timeout", "4")),
|
||||
bbox_token_("!bbox!"),
|
||||
scale_denom_token_("!scale_denominator!"),
|
||||
pixel_width_token_("!pixel_width!"),
|
||||
pixel_height_token_("!pixel_height!"),
|
||||
persist_connection_(*params_.get<mapnik::boolean>("persist_connection", true)),
|
||||
extent_from_subquery_(*params_.get<mapnik::boolean>("extent_from_subquery", false)),
|
||||
// params below are for testing purposes only (will likely be removed at any time)
|
||||
intersect_min_scale_(*params_.get<int>("intersect_min_scale", 0)),
|
||||
intersect_max_scale_(*params_.get<int>("intersect_max_scale", 0))
|
||||
{
|
||||
if (table_.empty())
|
||||
{
|
||||
|
@ -128,7 +128,7 @@ void postgis_datasource::bind() const
|
|||
if (conn && conn->isOK())
|
||||
{
|
||||
PoolGuard<shared_ptr<Connection>,
|
||||
shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
|
||||
desc_.set_encoding(conn->client_encoding());
|
||||
|
||||
|
@ -160,46 +160,49 @@ void postgis_datasource::bind() const
|
|||
#ifdef MAPNIK_STATS
|
||||
mapnik::progress_timer __stats2__(std::clog, "postgis_datasource::bind(get_srid_and_geometry_column)");
|
||||
#endif
|
||||
|
||||
std::ostringstream s;
|
||||
s << "SELECT f_geometry_column, srid FROM "
|
||||
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
|
||||
<< mapnik::sql_utils::unquote_double(geometry_table_)
|
||||
<< "'";
|
||||
|
||||
if (! schema_.empty())
|
||||
try
|
||||
{
|
||||
s << " AND f_table_schema='"
|
||||
<< mapnik::sql_utils::unquote_double(schema_)
|
||||
s << "SELECT f_geometry_column, srid FROM "
|
||||
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
|
||||
<< mapnik::sql_utils::unquote_double(geometry_table_)
|
||||
<< "'";
|
||||
}
|
||||
|
||||
if (! geometry_field_.empty())
|
||||
{
|
||||
s << " AND f_geometry_column='"
|
||||
<< mapnik::sql_utils::unquote_double(geometry_field_)
|
||||
<< "'";
|
||||
}
|
||||
|
||||
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
|
||||
if (rs->next())
|
||||
{
|
||||
geometryColumn_ = rs->getValue("f_geometry_column");
|
||||
|
||||
if (srid_ == 0)
|
||||
if (! schema_.empty())
|
||||
{
|
||||
const char* srid_c = rs->getValue("srid");
|
||||
if (srid_c != NULL)
|
||||
s << " AND f_table_schema='"
|
||||
<< mapnik::sql_utils::unquote_double(schema_)
|
||||
<< "'";
|
||||
}
|
||||
if (! geometry_field_.empty())
|
||||
{
|
||||
s << " AND f_geometry_column='"
|
||||
<< mapnik::sql_utils::unquote_double(geometry_field_)
|
||||
<< "'";
|
||||
}
|
||||
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
|
||||
if (rs->next())
|
||||
{
|
||||
geometryColumn_ = rs->getValue("f_geometry_column");
|
||||
if (srid_ == 0)
|
||||
{
|
||||
int result = 0;
|
||||
if (mapnik::util::string2int(srid_c, result))
|
||||
const char* srid_c = rs->getValue("srid");
|
||||
if (srid_c != NULL)
|
||||
{
|
||||
srid_ = result;
|
||||
int result = 0;
|
||||
if (mapnik::util::string2int(srid_c, result))
|
||||
{
|
||||
srid_ = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rs->close();
|
||||
}
|
||||
catch (mapnik::datasource_exception const& ex) {
|
||||
// let this pass on query error and use the fallback below
|
||||
MAPNIK_LOG_WARN(postgis) << "postgis_datasource: metadata query failed: " << ex.what();
|
||||
}
|
||||
rs->close();
|
||||
|
||||
// If we still do not know the srid then we can try to fetch
|
||||
// it from the 'table_' parameter, which should work even if it is
|
||||
|
@ -386,6 +389,7 @@ void postgis_datasource::bind() const
|
|||
case 701: // float8
|
||||
case 1700: // numeric
|
||||
desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Double));
|
||||
break;
|
||||
case 1042: // bpchar
|
||||
case 1043: // varchar
|
||||
case 25: // text
|
||||
|
@ -649,14 +653,14 @@ featureset_ptr postgis_datasource::features(const query& q) const
|
|||
s << "SELECT ST_AsBinary(";
|
||||
|
||||
if (simplify_geometries_) {
|
||||
s << "ST_Simplify(";
|
||||
s << "ST_Simplify(";
|
||||
}
|
||||
|
||||
s << "\"" << geometryColumn_ << "\"";
|
||||
|
||||
if (simplify_geometries_) {
|
||||
const double tolerance = std::min(px_gw, px_gh) / 2.0;
|
||||
s << ", " << tolerance << ")";
|
||||
const double tolerance = std::min(px_gw, px_gh) / 2.0;
|
||||
s << ", " << tolerance << ")";
|
||||
}
|
||||
|
||||
s << ") AS geom";
|
||||
|
@ -703,7 +707,16 @@ featureset_ptr postgis_datasource::features(const query& q) const
|
|||
}
|
||||
else
|
||||
{
|
||||
throw mapnik::datasource_exception("Postgis Plugin: bad connection");
|
||||
std::string err_msg = "Postgis Plugin:";
|
||||
if (conn)
|
||||
{
|
||||
err_msg += conn->status();
|
||||
}
|
||||
else
|
||||
{
|
||||
err_msg += " Null connection";
|
||||
}
|
||||
throw mapnik::datasource_exception(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -919,50 +932,53 @@ boost::optional<mapnik::datasource::geometry_t> postgis_datasource::get_geometry
|
|||
|
||||
std::ostringstream s;
|
||||
std::string g_type;
|
||||
|
||||
s << "SELECT lower(type) as type FROM "
|
||||
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
|
||||
<< mapnik::sql_utils::unquote_double(geometry_table_)
|
||||
<< "'";
|
||||
|
||||
if (! schema_.empty())
|
||||
try
|
||||
{
|
||||
s << " AND f_table_schema='"
|
||||
<< mapnik::sql_utils::unquote_double(schema_)
|
||||
s << "SELECT lower(type) as type FROM "
|
||||
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
|
||||
<< mapnik::sql_utils::unquote_double(geometry_table_)
|
||||
<< "'";
|
||||
if (! schema_.empty())
|
||||
{
|
||||
s << " AND f_table_schema='"
|
||||
<< mapnik::sql_utils::unquote_double(schema_)
|
||||
<< "'";
|
||||
}
|
||||
if (! geometry_field_.empty())
|
||||
{
|
||||
s << " AND f_geometry_column='"
|
||||
<< mapnik::sql_utils::unquote_double(geometry_field_)
|
||||
<< "'";
|
||||
}
|
||||
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
|
||||
if (rs->next())
|
||||
{
|
||||
g_type = rs->getValue("type");
|
||||
if (boost::algorithm::contains(g_type, "line"))
|
||||
{
|
||||
result.reset(mapnik::datasource::LineString);
|
||||
return result;
|
||||
}
|
||||
else if (boost::algorithm::contains(g_type, "point"))
|
||||
{
|
||||
result.reset(mapnik::datasource::Point);
|
||||
return result;
|
||||
}
|
||||
else if (boost::algorithm::contains(g_type, "polygon"))
|
||||
{
|
||||
result.reset(mapnik::datasource::Polygon);
|
||||
return result;
|
||||
}
|
||||
else // geometry
|
||||
{
|
||||
result.reset(mapnik::datasource::Collection);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! geometry_field_.empty())
|
||||
{
|
||||
s << " AND f_geometry_column='"
|
||||
<< mapnik::sql_utils::unquote_double(geometry_field_)
|
||||
<< "'";
|
||||
}
|
||||
|
||||
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
|
||||
if (rs->next())
|
||||
{
|
||||
g_type = rs->getValue("type");
|
||||
if (boost::algorithm::contains(g_type, "line"))
|
||||
{
|
||||
result.reset(mapnik::datasource::LineString);
|
||||
return result;
|
||||
}
|
||||
else if (boost::algorithm::contains(g_type, "point"))
|
||||
{
|
||||
result.reset(mapnik::datasource::Point);
|
||||
return result;
|
||||
}
|
||||
else if (boost::algorithm::contains(g_type, "polygon"))
|
||||
{
|
||||
result.reset(mapnik::datasource::Polygon);
|
||||
return result;
|
||||
}
|
||||
else // geometry
|
||||
{
|
||||
result.reset(mapnik::datasource::Collection);
|
||||
return result;
|
||||
}
|
||||
catch (mapnik::datasource_exception const& ex) {
|
||||
// let this pass on query error and use the fallback below
|
||||
MAPNIK_LOG_WARN(postgis) << "postgis_datasource: metadata query failed: " << ex.what();
|
||||
}
|
||||
|
||||
// fallback to querying first several features
|
||||
|
|
|
@ -14,7 +14,8 @@ plugin_env = plugin_base.Clone()
|
|||
plugin_sources = Split(
|
||||
"""
|
||||
%(PLUGIN_NAME)s_datasource.cpp
|
||||
%(PLUGIN_NAME)s_featureset.cpp
|
||||
%(PLUGIN_NAME)s_featureset.cpp
|
||||
%(PLUGIN_NAME)s_utils.cpp
|
||||
""" % locals()
|
||||
)
|
||||
|
||||
|
|
|
@ -69,38 +69,34 @@ void python_datasource::bind() const
|
|||
// if no factory callable is defined, bind is a nop
|
||||
if (factory_.empty()) return;
|
||||
|
||||
// split factory at ':' to parse out module and callable
|
||||
std::vector<std::string> factory_split;
|
||||
split(factory_split, factory_, is_any_of(":"));
|
||||
if ((factory_split.size() < 1) || (factory_split.size() > 2))
|
||||
{
|
||||
// FIMXE: is this appropriate error reporting?
|
||||
std::cerr << "python: factory string must be of the form '[module:]callable' when parsing \""
|
||||
<< factory_ << '"' << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// extract the module and the callable
|
||||
str module_name("__main__"), callable_name;
|
||||
if (factory_split.size() == 1)
|
||||
{
|
||||
callable_name = str(factory_split[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
module_name = str(factory_split[0]);
|
||||
callable_name = str(factory_split[1]);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// split factory at ':' to parse out module and callable
|
||||
std::vector<std::string> factory_split;
|
||||
split(factory_split, factory_, is_any_of(":"));
|
||||
if ((factory_split.size() < 1) || (factory_split.size() > 2))
|
||||
{
|
||||
throw mapnik::datasource_exception(
|
||||
std::string("python: factory string must be of the form '[module:]callable' when parsing \"")
|
||||
+ factory_ + '"');
|
||||
}
|
||||
// extract the module and the callable
|
||||
str module_name("__main__"), callable_name;
|
||||
if (factory_split.size() == 1)
|
||||
{
|
||||
callable_name = str(factory_split[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
module_name = str(factory_split[0]);
|
||||
callable_name = str(factory_split[1]);
|
||||
}
|
||||
ensure_gil lock;
|
||||
|
||||
// import the main module from Python (in case we're embedding the
|
||||
// interpreter directly) and also import the callable.
|
||||
object main_module = import("__main__");
|
||||
object callable_module = import(module_name);
|
||||
object callable = callable_module.attr(callable_name);
|
||||
|
||||
// prepare the arguments
|
||||
dict kwargs;
|
||||
typedef std::map<std::string, std::string>::value_type kv_type;
|
||||
|
@ -112,6 +108,10 @@ void python_datasource::bind() const
|
|||
// get our wrapped data source
|
||||
datasource_ = callable(*boost::python::make_tuple(), **kwargs);
|
||||
}
|
||||
catch ( error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
|
||||
is_bound_ = true;
|
||||
}
|
||||
|
@ -124,11 +124,18 @@ mapnik::datasource::datasource_t python_datasource::type() const
|
|||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
ensure_gil lock;
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
object data_type = datasource_.attr("data_type");
|
||||
long data_type_integer = extract<long>(data_type);
|
||||
return mapnik::datasource::datasource_t(data_type_integer);
|
||||
}
|
||||
catch ( error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
|
||||
object data_type = datasource_.attr("data_type");
|
||||
long data_type_integer = extract<long>(data_type);
|
||||
return mapnik::datasource::datasource_t(data_type_integer);
|
||||
}
|
||||
|
||||
mapnik::box2d<double> python_datasource::envelope() const
|
||||
|
@ -137,8 +144,15 @@ mapnik::box2d<double> python_datasource::envelope() const
|
|||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
ensure_gil lock;
|
||||
return extract<mapnik::box2d<double> >(datasource_.attr("envelope"));
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
return extract<mapnik::box2d<double> >(datasource_.attr("envelope"));
|
||||
}
|
||||
catch ( error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<mapnik::datasource::geometry_t> python_datasource::get_geometry_type() const
|
||||
|
@ -149,20 +163,27 @@ boost::optional<mapnik::datasource::geometry_t> python_datasource::get_geometry_
|
|||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
ensure_gil lock;
|
||||
|
||||
// if the datasource object has no geometry_type attribute, return a 'none' value
|
||||
if (!PyObject_HasAttrString(datasource_.ptr(), "geometry_type"))
|
||||
return return_type();
|
||||
|
||||
object py_geometry_type = datasource_.attr("geometry_type");
|
||||
|
||||
// if the attribute value is 'None', return a 'none' value
|
||||
if (py_geometry_type.ptr() == object().ptr())
|
||||
return return_type();
|
||||
|
||||
long geom_type_integer = extract<long>(py_geometry_type);
|
||||
return mapnik::datasource::geometry_t(geom_type_integer);
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
// if the datasource object has no geometry_type attribute, return a 'none' value
|
||||
if (!PyObject_HasAttrString(datasource_.ptr(), "geometry_type"))
|
||||
{
|
||||
return return_type();
|
||||
}
|
||||
object py_geometry_type = datasource_.attr("geometry_type");
|
||||
// if the attribute value is 'None', return a 'none' value
|
||||
if (py_geometry_type.ptr() == object().ptr())
|
||||
{
|
||||
return return_type();
|
||||
}
|
||||
long geom_type_integer = extract<long>(py_geometry_type);
|
||||
return mapnik::datasource::geometry_t(geom_type_integer);
|
||||
}
|
||||
catch ( error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
}
|
||||
|
||||
mapnik::featureset_ptr python_datasource::features(mapnik::query const& q) const
|
||||
|
@ -171,22 +192,27 @@ mapnik::featureset_ptr python_datasource::features(mapnik::query const& q) const
|
|||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
// if the query box intersects our world extent then query for features
|
||||
if (envelope().intersects(q.get_bbox()))
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
|
||||
object features(datasource_.attr("features")(q));
|
||||
|
||||
// if 'None' was returned, return an empty feature set
|
||||
if(features.ptr() == object().ptr())
|
||||
return mapnik::featureset_ptr();
|
||||
|
||||
return boost::make_shared<python_featureset>(features);
|
||||
// if the query box intersects our world extent then query for features
|
||||
if (envelope().intersects(q.get_bbox()))
|
||||
{
|
||||
ensure_gil lock;
|
||||
object features(datasource_.attr("features")(q));
|
||||
// if 'None' was returned, return an empty feature set
|
||||
if(features.ptr() == object().ptr())
|
||||
{
|
||||
return mapnik::featureset_ptr();
|
||||
}
|
||||
return boost::make_shared<python_featureset>(features);
|
||||
}
|
||||
// otherwise return an empty featureset pointer
|
||||
return mapnik::featureset_ptr();
|
||||
}
|
||||
catch ( error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
|
||||
// otherwise return an empty featureset pointer
|
||||
return mapnik::featureset_ptr();
|
||||
}
|
||||
|
||||
mapnik::featureset_ptr python_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
|
||||
|
@ -195,14 +221,21 @@ mapnik::featureset_ptr python_datasource::features_at_point(mapnik::coord2d cons
|
|||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
ensure_gil lock;
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
object features(datasource_.attr("features_at_point")(pt));
|
||||
// if we returned none, return an empty set
|
||||
if(features.ptr() == object().ptr())
|
||||
{
|
||||
return mapnik::featureset_ptr();
|
||||
}
|
||||
// otherwise, return a feature set which can iterate over the iterator
|
||||
return boost::make_shared<python_featureset>(features);
|
||||
}
|
||||
catch ( error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
|
||||
object features(datasource_.attr("features_at_point")(pt));
|
||||
|
||||
// if we returned none, return an empty set
|
||||
if(features.ptr() == object().ptr())
|
||||
return mapnik::featureset_ptr();
|
||||
|
||||
// otherwise, return a feature set which can iterate over the iterator
|
||||
return boost::make_shared<python_featureset>(features);
|
||||
}
|
||||
|
|
23
plugins/input/python/python_utils.cpp
Normal file
23
plugins/input/python/python_utils.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "python_utils.hpp"
|
||||
|
||||
std::string extractException()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
PyObject *exc,*val,*tb;
|
||||
PyErr_Fetch(&exc,&val,&tb);
|
||||
PyErr_NormalizeException(&exc,&val,&tb);
|
||||
handle<> hexc(exc),hval(allow_null(val)),htb(allow_null(tb));
|
||||
if(!hval)
|
||||
{
|
||||
return extract<std::string>(str(hexc));
|
||||
}
|
||||
else
|
||||
{
|
||||
object traceback(import("traceback"));
|
||||
object format_exception(traceback.attr("format_exception"));
|
||||
object formatted_list(format_exception(hexc,hval,htb));
|
||||
object formatted(str("").join(formatted_list));
|
||||
return extract<std::string>(formatted);
|
||||
}
|
||||
}
|
|
@ -13,4 +13,6 @@ class ensure_gil
|
|||
PyGILState_STATE gil_state_;
|
||||
};
|
||||
|
||||
std::string extractException();
|
||||
|
||||
#endif // PYTHON_UTILS_HPP
|
||||
|
|
|
@ -57,7 +57,7 @@ shape_featureset<filterT>::shape_featureset(filterT const& filter,
|
|||
template <typename filterT>
|
||||
feature_ptr shape_featureset<filterT>::next()
|
||||
{
|
||||
if (row_limit_ && count_ > row_limit_)
|
||||
if (row_limit_ && count_ >= row_limit_)
|
||||
{
|
||||
return feature_ptr();
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ shape_index_featureset<filterT>::shape_index_featureset(filterT const& filter,
|
|||
template <typename filterT>
|
||||
feature_ptr shape_index_featureset<filterT>::next()
|
||||
{
|
||||
if (row_limit_ && count_ > row_limit_)
|
||||
if (row_limit_ && count_ >= row_limit_)
|
||||
{
|
||||
return feature_ptr();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <mapnik/agg_rasterizer.hpp>
|
||||
|
||||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/geom_util.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/vertex_converters.hpp>
|
||||
|
@ -136,10 +137,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -172,10 +170,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
else // raster markers
|
||||
|
@ -207,11 +202,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,10 @@ void agg_renderer<T>::process(raster_symbolizer const& sym,
|
|||
}
|
||||
if (premultiply_source)
|
||||
{
|
||||
agg::rendering_buffer buffer(source->data_.getBytes(),source->data_.width(),source->data_.height(),source->data_.width() * 4);
|
||||
agg::rendering_buffer buffer(source->data_.getBytes(),
|
||||
source->data_.width(),
|
||||
source->data_.height(),
|
||||
source->data_.width() * 4);
|
||||
agg::pixfmt_rgba32 pixf(buffer);
|
||||
pixf.premultiply();
|
||||
}
|
||||
|
@ -100,7 +103,10 @@ void agg_renderer<T>::process(raster_symbolizer const& sym,
|
|||
{
|
||||
if (scaling_method == SCALING_BILINEAR8)
|
||||
{
|
||||
scale_image_bilinear8<image_data_32>(target.data_,source->data_, 0.0, 0.0);
|
||||
scale_image_bilinear8<image_data_32>(target.data_,
|
||||
source->data_,
|
||||
0.0,
|
||||
0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
41
src/build.py
41
src/build.py
|
@ -100,6 +100,7 @@ else: # unix, non-macos
|
|||
|
||||
source = Split(
|
||||
"""
|
||||
miniz_png.cpp
|
||||
color.cpp
|
||||
css_color_grammar.cpp
|
||||
conversions.cpp
|
||||
|
@ -292,26 +293,26 @@ source += Split(
|
|||
""")
|
||||
|
||||
# https://github.com/mapnik/mapnik/issues/1438
|
||||
#if env['SVG_RENDERER']: # svg backend
|
||||
# source += Split(
|
||||
# """
|
||||
# svg/output/svg_renderer.cpp
|
||||
# svg/output/svg_generator.cpp
|
||||
# svg/output/svg_output_attributes.cpp
|
||||
# svg/output/process_symbolizers.cpp
|
||||
# svg/output/process_building_symbolizer.cpp
|
||||
# svg/output/process_line_pattern_symbolizer.cpp
|
||||
# svg/output/process_line_symbolizer.cpp
|
||||
# svg/output/process_markers_symbolizer.cpp
|
||||
# svg/output/process_point_symbolizer.cpp
|
||||
# svg/output/process_polygon_pattern_symbolizer.cpp
|
||||
# svg/output/process_polygon_symbolizer.cpp
|
||||
# svg/output/process_raster_symbolizer.cpp
|
||||
# svg/output/process_shield_symbolizer.cpp
|
||||
# svg/output/process_text_symbolizer.cpp
|
||||
# """)
|
||||
# lib_env.Append(CXXFLAGS = '-DSVG_RENDERER')
|
||||
# libmapnik_cxxflags.append('-DSVG_RENDERER')
|
||||
if env['SVG_RENDERER']: # svg backend
|
||||
source += Split(
|
||||
"""
|
||||
svg/output/svg_renderer.cpp
|
||||
svg/output/svg_generator.cpp
|
||||
svg/output/svg_output_attributes.cpp
|
||||
svg/output/process_symbolizers.cpp
|
||||
svg/output/process_building_symbolizer.cpp
|
||||
svg/output/process_line_pattern_symbolizer.cpp
|
||||
svg/output/process_line_symbolizer.cpp
|
||||
svg/output/process_markers_symbolizer.cpp
|
||||
svg/output/process_point_symbolizer.cpp
|
||||
svg/output/process_polygon_pattern_symbolizer.cpp
|
||||
svg/output/process_polygon_symbolizer.cpp
|
||||
svg/output/process_raster_symbolizer.cpp
|
||||
svg/output/process_shield_symbolizer.cpp
|
||||
svg/output/process_text_symbolizer.cpp
|
||||
""")
|
||||
lib_env.Append(CXXFLAGS = '-DSVG_RENDERER')
|
||||
libmapnik_cxxflags.append('-DSVG_RENDERER')
|
||||
|
||||
if env['XMLPARSER'] == 'libxml2' and env['HAS_LIBXML2']:
|
||||
source += Split(
|
||||
|
|
|
@ -1750,10 +1750,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1778,10 +1775,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
else // raster markers
|
||||
|
@ -1811,10 +1805,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
// stl
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mapnik {
|
||||
|
@ -73,8 +74,17 @@ datasource_ptr datasource_cache::create(const parameters& params, bool bind)
|
|||
std::map<std::string,boost::shared_ptr<PluginInfo> >::iterator itr=plugins_.find(*type);
|
||||
if ( itr == plugins_.end() )
|
||||
{
|
||||
throw config_error(std::string("Could not create datasource. No plugin ") +
|
||||
"found for type '" + * type + "' (searched in: " + plugin_directories() + ")");
|
||||
std::ostringstream s;
|
||||
s << "Could not create datasource for type: '" << *type << "'";
|
||||
if (plugin_directories_.empty())
|
||||
{
|
||||
s << " (no datasource plugin directories have been successfully registered)";
|
||||
}
|
||||
else
|
||||
{
|
||||
s << " (searched for datasource plugins in '" << plugin_directories() << "')";
|
||||
}
|
||||
throw config_error(s.str());
|
||||
}
|
||||
|
||||
if ( ! itr->second->handle())
|
||||
|
|
|
@ -112,7 +112,7 @@ struct expression_string : boost::static_visitor<void>
|
|||
#else
|
||||
str_ += x.pattern.str();
|
||||
str_ +="','";
|
||||
str_ += x.pattern.str();
|
||||
str_ += x.format;
|
||||
#endif
|
||||
str_ +="')";
|
||||
}
|
||||
|
|
|
@ -65,6 +65,18 @@ hit_grid<T>::hit_grid(hit_grid<T> const& rhs)
|
|||
data_.set(base_mask);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void hit_grid<T>::clear()
|
||||
{
|
||||
painted_ = false;
|
||||
f_keys_.clear();
|
||||
features_.clear();
|
||||
names_.clear();
|
||||
f_keys_[base_mask] = "";
|
||||
data_.set(base_mask);
|
||||
ctx_ = boost::make_shared<mapnik::context_type>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void hit_grid<T>::add_feature(mapnik::feature_impl & feature)
|
||||
{
|
||||
|
|
|
@ -163,10 +163,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -208,10 +205,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
else // raster markers
|
||||
|
@ -256,10 +250,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ extern "C"
|
|||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/png_io.hpp>
|
||||
#include <mapnik/tiff_io.hpp>
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/memory.hpp>
|
||||
#include <mapnik/image_view.hpp>
|
||||
|
@ -111,7 +112,8 @@ void handle_png_options(std::string const& type,
|
|||
int * strategy,
|
||||
int * trans_mode,
|
||||
double * gamma,
|
||||
bool * use_octree)
|
||||
bool * use_octree,
|
||||
bool * use_miniz)
|
||||
{
|
||||
if (type == "png" || type == "png24" || type == "png32")
|
||||
{
|
||||
|
@ -138,19 +140,20 @@ void handle_png_options(std::string const& type,
|
|||
{
|
||||
*use_octree = true;
|
||||
}
|
||||
else if (t == "e=miniz")
|
||||
{
|
||||
*use_miniz = true;
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "c="))
|
||||
{
|
||||
if (*colors < 0)
|
||||
throw ImageWriterException("invalid color parameter: unavailable for true color images");
|
||||
|
||||
if (!mapnik::util::string2int(t.substr(2),*colors) || *colors < 0 || *colors > 256)
|
||||
if (!mapnik::util::string2int(t.substr(2),*colors) || *colors < 1 || *colors > 256)
|
||||
throw ImageWriterException("invalid color parameter: " + t.substr(2));
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "t="))
|
||||
{
|
||||
if (*colors < 0)
|
||||
throw ImageWriterException("invalid trans_mode parameter: unavailable for true color images");
|
||||
|
||||
if (!mapnik::util::string2int(t.substr(2),*trans_mode) || *trans_mode < 0 || *trans_mode > 2)
|
||||
throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2));
|
||||
}
|
||||
|
@ -173,9 +176,9 @@ void handle_png_options(std::string const& type,
|
|||
*/
|
||||
if (!mapnik::util::string2int(t.substr(2),*compression)
|
||||
|| *compression < Z_DEFAULT_COMPRESSION
|
||||
|| *compression > Z_BEST_COMPRESSION)
|
||||
|| *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 9 are valid)");
|
||||
throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 10 are valid)");
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "s="))
|
||||
|
@ -197,12 +200,20 @@ void handle_png_options(std::string const& type,
|
|||
{
|
||||
*strategy = Z_RLE;
|
||||
}
|
||||
else if (s == "fixed")
|
||||
{
|
||||
*strategy = Z_FIXED;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ImageWriterException("invalid compression strategy parameter: " + s);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((*use_miniz == false) && *compression > Z_BEST_COMPRESSION)
|
||||
{
|
||||
throw ImageWriterException("invalid compression value: (only -1 through 9 are valid)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,6 +235,7 @@ void save_to_stream(T const& image,
|
|||
int trans_mode = -1;
|
||||
double gamma = -1;
|
||||
bool use_octree = true;
|
||||
bool use_miniz = false;
|
||||
|
||||
handle_png_options(t,
|
||||
&colors,
|
||||
|
@ -231,16 +243,25 @@ void save_to_stream(T const& image,
|
|||
&strategy,
|
||||
&trans_mode,
|
||||
&gamma,
|
||||
&use_octree);
|
||||
&use_octree,
|
||||
&use_miniz);
|
||||
|
||||
if (palette.valid())
|
||||
save_as_png8_pal(stream, image, palette, compression, strategy);
|
||||
{
|
||||
save_as_png8_pal(stream, image, palette, compression, strategy, use_miniz);
|
||||
}
|
||||
else if (colors < 0)
|
||||
save_as_png(stream, image, compression, strategy);
|
||||
{
|
||||
save_as_png(stream, image, compression, strategy, trans_mode, use_miniz);
|
||||
}
|
||||
else if (use_octree)
|
||||
save_as_png8_oct(stream, image, colors, compression, strategy);
|
||||
{
|
||||
save_as_png8_oct(stream, image, colors, compression, strategy, trans_mode, use_miniz);
|
||||
}
|
||||
else
|
||||
save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma);
|
||||
{
|
||||
save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma, use_miniz);
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "tif"))
|
||||
{
|
||||
|
@ -270,11 +291,12 @@ void save_to_stream(T const& image,
|
|||
if (t == "png" || boost::algorithm::starts_with(t, "png"))
|
||||
{
|
||||
int colors = 256;
|
||||
int compression = Z_DEFAULT_COMPRESSION;
|
||||
int compression = Z_DEFAULT_COMPRESSION; // usually mapped to z=6 in zlib
|
||||
int strategy = Z_DEFAULT_STRATEGY;
|
||||
int trans_mode = -1;
|
||||
double gamma = -1;
|
||||
bool use_octree = true;
|
||||
bool use_miniz = false;
|
||||
|
||||
handle_png_options(t,
|
||||
&colors,
|
||||
|
@ -282,14 +304,21 @@ void save_to_stream(T const& image,
|
|||
&strategy,
|
||||
&trans_mode,
|
||||
&gamma,
|
||||
&use_octree);
|
||||
&use_octree,
|
||||
&use_miniz);
|
||||
|
||||
if (colors < 0)
|
||||
save_as_png(stream, image, compression, strategy);
|
||||
{
|
||||
save_as_png(stream, image, compression, strategy, trans_mode, use_miniz);
|
||||
}
|
||||
else if (use_octree)
|
||||
save_as_png8_oct(stream, image, colors, compression, strategy);
|
||||
{
|
||||
save_as_png8_oct(stream, image, colors, compression, strategy, trans_mode, use_miniz);
|
||||
}
|
||||
else
|
||||
save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma);
|
||||
{
|
||||
save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma, use_miniz);
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::starts_with(t, "tif"))
|
||||
{
|
||||
|
|
|
@ -1050,6 +1050,10 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym)
|
|||
|
||||
marker_placement_e placement = sym.get_attr<marker_placement_e>("placement",symbol.get_marker_placement());
|
||||
symbol.set_marker_placement(placement);
|
||||
|
||||
marker_multi_policy_e mpolicy = sym.get_attr<marker_multi_policy_e>("multi-policy",symbol.get_marker_multi_policy());
|
||||
symbol.set_marker_multi_policy(mpolicy);
|
||||
|
||||
parse_symbolizer_base(symbol, sym);
|
||||
rule.append(symbol);
|
||||
}
|
||||
|
@ -1664,7 +1668,7 @@ void map_parser::ensure_exists(std::string const& file_path)
|
|||
{
|
||||
if (!boost::filesystem::exists(file_path))
|
||||
{
|
||||
throw mapnik::config_error("point-file could not be found: '" + file_path + "'");
|
||||
throw mapnik::config_error("file could not be found: '" + file_path + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
22
src/map.cpp
22
src/map.cpp
|
@ -238,7 +238,9 @@ unsigned Map::height() const
|
|||
|
||||
void Map::set_width(unsigned width)
|
||||
{
|
||||
if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE)
|
||||
if (width != width_ &&
|
||||
width >= MIN_MAPSIZE &&
|
||||
width <= MAX_MAPSIZE)
|
||||
{
|
||||
width_=width;
|
||||
fixAspectRatio();
|
||||
|
@ -247,7 +249,9 @@ void Map::set_width(unsigned width)
|
|||
|
||||
void Map::set_height(unsigned height)
|
||||
{
|
||||
if (height >= MIN_MAPSIZE && height <= MAX_MAPSIZE)
|
||||
if (height != height_ &&
|
||||
height >= MIN_MAPSIZE &&
|
||||
height <= MAX_MAPSIZE)
|
||||
{
|
||||
height_=height;
|
||||
fixAspectRatio();
|
||||
|
@ -256,8 +260,12 @@ void Map::set_height(unsigned height)
|
|||
|
||||
void Map::resize(unsigned width,unsigned height)
|
||||
{
|
||||
if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE &&
|
||||
height >= MIN_MAPSIZE && height <= MAX_MAPSIZE)
|
||||
if (width != width_ &&
|
||||
height != height_ &&
|
||||
width >= MIN_MAPSIZE &&
|
||||
width <= MAX_MAPSIZE &&
|
||||
height >= MIN_MAPSIZE &&
|
||||
height <= MAX_MAPSIZE)
|
||||
{
|
||||
width_=width;
|
||||
height_=height;
|
||||
|
@ -346,8 +354,10 @@ void Map::zoom_all()
|
|||
{
|
||||
try
|
||||
{
|
||||
if (!layers_.size() > 0)
|
||||
if (layers_.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
projection proj0(srs_);
|
||||
box2d<double> ext;
|
||||
bool success = false;
|
||||
|
@ -575,7 +585,7 @@ featureset_ptr Map::query_point(unsigned index, double x, double y) const
|
|||
{
|
||||
std::ostringstream s;
|
||||
s << "Invalid layer index passed to query_point: '" << index << "'";
|
||||
if (layers_.size() > 0) s << " for map with " << layers_.size() << " layers(s)";
|
||||
if (!layers_.empty()) s << " for map with " << layers_.size() << " layers(s)";
|
||||
else s << " (map has no layers)";
|
||||
throw std::out_of_range(s.str());
|
||||
}
|
||||
|
|
|
@ -37,6 +37,15 @@ static const char * marker_placement_strings[] = {
|
|||
|
||||
IMPLEMENT_ENUM( marker_placement_e, marker_placement_strings )
|
||||
|
||||
static const char * marker_multi_policy_strings[] = {
|
||||
"each",
|
||||
"whole",
|
||||
"largest",
|
||||
""
|
||||
};
|
||||
|
||||
IMPLEMENT_ENUM( marker_multi_policy_e, marker_multi_policy_strings )
|
||||
|
||||
markers_symbolizer::markers_symbolizer()
|
||||
: symbolizer_with_image(parse_path("shape://ellipse")),
|
||||
symbolizer_base(),
|
||||
|
@ -46,7 +55,10 @@ markers_symbolizer::markers_symbolizer()
|
|||
allow_overlap_(false),
|
||||
spacing_(100.0),
|
||||
max_error_(0.2),
|
||||
marker_p_(MARKER_POINT_PLACEMENT) { }
|
||||
marker_p_(MARKER_POINT_PLACEMENT),
|
||||
// TODO: consider defaulting to MARKER_WHOLE_MULTI,
|
||||
// for backward compatibility with 2.0.0
|
||||
marker_mp_(MARKER_EACH_MULTI) { }
|
||||
|
||||
markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
||||
: symbolizer_with_image(filename),
|
||||
|
@ -57,7 +69,10 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
|||
allow_overlap_(false),
|
||||
spacing_(100.0),
|
||||
max_error_(0.2),
|
||||
marker_p_(MARKER_POINT_PLACEMENT) { }
|
||||
marker_p_(MARKER_POINT_PLACEMENT),
|
||||
// TODO: consider defaulting to MARKER_WHOLE_MULTI,
|
||||
// for backward compatibility with 2.0.0
|
||||
marker_mp_(MARKER_EACH_MULTI) { }
|
||||
|
||||
markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
||||
: symbolizer_with_image(rhs),
|
||||
|
@ -71,7 +86,8 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
|||
fill_(rhs.fill_),
|
||||
fill_opacity_(rhs.fill_opacity_),
|
||||
stroke_(rhs.stroke_),
|
||||
marker_p_(rhs.marker_p_) {}
|
||||
marker_p_(rhs.marker_p_),
|
||||
marker_mp_(rhs.marker_mp_) {}
|
||||
|
||||
void markers_symbolizer::set_ignore_placement(bool ignore_placement)
|
||||
{
|
||||
|
@ -173,4 +189,14 @@ marker_placement_e markers_symbolizer::get_marker_placement() const
|
|||
return marker_p_;
|
||||
}
|
||||
|
||||
void markers_symbolizer::set_marker_multi_policy(marker_multi_policy_e marker_mp)
|
||||
{
|
||||
marker_mp_ = marker_mp;
|
||||
}
|
||||
|
||||
marker_multi_policy_e markers_symbolizer::get_marker_multi_policy() const
|
||||
{
|
||||
return marker_mp_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,9 +62,10 @@ struct accumulate_extent
|
|||
bool first_;
|
||||
};
|
||||
|
||||
memory_datasource::memory_datasource()
|
||||
memory_datasource::memory_datasource(datasource::datasource_t type)
|
||||
: datasource(parameters()),
|
||||
desc_("in-memory datasource","utf-8") {}
|
||||
desc_("in-memory datasource","utf-8"),
|
||||
type_(type) {}
|
||||
|
||||
memory_datasource::~memory_datasource() {}
|
||||
|
||||
|
@ -77,7 +78,7 @@ void memory_datasource::push(feature_ptr feature)
|
|||
|
||||
datasource::datasource_t memory_datasource::type() const
|
||||
{
|
||||
return datasource::Vector;
|
||||
return type_;
|
||||
}
|
||||
|
||||
featureset_ptr memory_datasource::features(const query& q) const
|
||||
|
|
4834
src/miniz.c
Normal file
4834
src/miniz.c
Normal file
File diff suppressed because it is too large
Load diff
365
src/miniz_png.cpp
Normal file
365
src/miniz_png.cpp
Normal file
|
@ -0,0 +1,365 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 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 <mapnik/palette.hpp>
|
||||
#include <mapnik/miniz_png.hpp>
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/image_view.hpp>
|
||||
|
||||
// miniz
|
||||
#define MINIZ_NO_ARCHIVE_APIS
|
||||
#define MINIZ_NO_STDIO
|
||||
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
|
||||
#include "miniz.c"
|
||||
|
||||
// zlib
|
||||
#include <zlib.h>
|
||||
|
||||
// stl
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mapnik { namespace MiniZ {
|
||||
|
||||
PNGWriter::PNGWriter(int level, int strategy)
|
||||
{
|
||||
buffer = NULL;
|
||||
compressor = NULL;
|
||||
|
||||
if (level == -1)
|
||||
{
|
||||
level = MZ_DEFAULT_LEVEL; // 6
|
||||
}
|
||||
else if (level < 0 || level > 10)
|
||||
{
|
||||
throw std::runtime_error("compression level must be between 0 and 10");
|
||||
}
|
||||
mz_uint flags = s_tdefl_num_probes[level] | (level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0 | TDEFL_WRITE_ZLIB_HEADER;
|
||||
if (strategy == Z_FILTERED) flags |= TDEFL_FILTER_MATCHES;
|
||||
else if (strategy == Z_HUFFMAN_ONLY) flags &= ~TDEFL_MAX_PROBES_MASK;
|
||||
else if (strategy == Z_RLE) flags |= TDEFL_RLE_MATCHES;
|
||||
else if (strategy == Z_FIXED) flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
|
||||
|
||||
buffer = (tdefl_output_buffer *)MZ_MALLOC(sizeof(tdefl_output_buffer));
|
||||
if (buffer == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
buffer->m_pBuf = NULL;
|
||||
buffer->m_capacity = 8192;
|
||||
buffer->m_expandable = MZ_TRUE;
|
||||
buffer->m_pBuf = (mz_uint8 *)MZ_MALLOC(buffer->m_capacity);
|
||||
if (buffer->m_pBuf == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
compressor = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
|
||||
if (compressor == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
// Reset output buffer.
|
||||
buffer->m_size = 0;
|
||||
tdefl_status tdstatus = tdefl_init(compressor, tdefl_output_buffer_putter, buffer, flags);
|
||||
if (tdstatus != TDEFL_STATUS_OKAY)
|
||||
{
|
||||
throw std::runtime_error("tdefl_init failed");
|
||||
}
|
||||
|
||||
// Write preamble.
|
||||
mz_bool status = tdefl_output_buffer_putter(preamble, 8, buffer);
|
||||
if (status != MZ_TRUE)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
PNGWriter::~PNGWriter()
|
||||
{
|
||||
if (compressor)
|
||||
{
|
||||
MZ_FREE(compressor);
|
||||
}
|
||||
if (buffer)
|
||||
{
|
||||
if (buffer->m_pBuf)
|
||||
{
|
||||
MZ_FREE(buffer->m_pBuf);
|
||||
}
|
||||
MZ_FREE(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
inline void PNGWriter::writeUInt32BE(mz_uint8 *target, mz_uint32 value)
|
||||
{
|
||||
target[0] = (value >> 24) & 0xFF;
|
||||
target[1] = (value >> 16) & 0xFF;
|
||||
target[2] = (value >> 8) & 0xFF;
|
||||
target[3] = value & 0xFF;
|
||||
}
|
||||
|
||||
size_t PNGWriter::startChunk(const mz_uint8 header[], size_t length)
|
||||
{
|
||||
size_t start = buffer->m_size;
|
||||
mz_bool status = tdefl_output_buffer_putter(header, length, buffer);
|
||||
if (status != MZ_TRUE)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
void PNGWriter::finishChunk(size_t start)
|
||||
{
|
||||
// Write chunk length at the beginning of the chunk.
|
||||
size_t payloadLength = buffer->m_size - start - 4 - 4;
|
||||
writeUInt32BE(buffer->m_pBuf + start, payloadLength);
|
||||
|
||||
// Write CRC32 checksum. Don't include the 4-byte length, but /do/ include
|
||||
// the 4-byte chunk name.
|
||||
mz_uint32 crc = mz_crc32(MZ_CRC32_INIT, buffer->m_pBuf + start + 4, payloadLength + 4);
|
||||
mz_uint8 checksum[] = { crc >> 24, crc >> 16, crc >> 8, crc };
|
||||
mz_bool status = tdefl_output_buffer_putter(checksum, 4, buffer);
|
||||
if (status != MZ_TRUE)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
void PNGWriter::writeIHDR(mz_uint32 width, mz_uint32 height, mz_uint8 pixel_depth)
|
||||
{
|
||||
// Write IHDR chunk.
|
||||
size_t IHDR = startChunk(IHDR_tpl, 21);
|
||||
writeUInt32BE(buffer->m_pBuf + IHDR + 8, width);
|
||||
writeUInt32BE(buffer->m_pBuf + IHDR + 12, height);
|
||||
|
||||
if (pixel_depth == 32)
|
||||
{
|
||||
// Alpha full color image.
|
||||
buffer->m_pBuf[IHDR + 16] = 8; // bit depth
|
||||
buffer->m_pBuf[IHDR + 17] = 6; // color type (6 == true color with alpha)
|
||||
}
|
||||
else if (pixel_depth == 24)
|
||||
{
|
||||
// Full color image.
|
||||
buffer->m_pBuf[IHDR + 16] = 8; // bit depth
|
||||
buffer->m_pBuf[IHDR + 17] = 2; // color type (2 == true color without alpha)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Paletted image.
|
||||
buffer->m_pBuf[IHDR + 16] = pixel_depth; // bit depth
|
||||
buffer->m_pBuf[IHDR + 17] = 3; // color type (3 == indexed color)
|
||||
}
|
||||
|
||||
buffer->m_pBuf[IHDR + 18] = 0; // compression method
|
||||
buffer->m_pBuf[IHDR + 19] = 0; // filter method
|
||||
buffer->m_pBuf[IHDR + 20] = 0; // interlace method
|
||||
finishChunk(IHDR);
|
||||
}
|
||||
|
||||
void PNGWriter::writePLTE(std::vector<rgb> const& palette)
|
||||
{
|
||||
// Write PLTE chunk.
|
||||
size_t PLTE = startChunk(PLTE_tpl, 8);
|
||||
const mz_uint8 *colors = reinterpret_cast<const mz_uint8 *>(&palette[0]);
|
||||
mz_bool status = tdefl_output_buffer_putter(colors, palette.size() * 3, buffer);
|
||||
if (status != MZ_TRUE)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
finishChunk(PLTE);
|
||||
}
|
||||
|
||||
void PNGWriter::writetRNS(std::vector<unsigned> const& alpha)
|
||||
{
|
||||
if (alpha.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> transparency(alpha.size());
|
||||
unsigned char transparencySize = 0; // Stores position of biggest to nonopaque value.
|
||||
for(unsigned i = 0; i < alpha.size(); i++)
|
||||
{
|
||||
transparency[i] = alpha[i];
|
||||
if (alpha[i] < 255)
|
||||
{
|
||||
transparencySize = i + 1;
|
||||
}
|
||||
}
|
||||
if (transparencySize > 0)
|
||||
{
|
||||
// Write tRNS chunk.
|
||||
size_t tRNS = startChunk(tRNS_tpl, 8);
|
||||
mz_bool status = tdefl_output_buffer_putter(&transparency[0], transparencySize, buffer);
|
||||
if (status != MZ_TRUE)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
finishChunk(tRNS);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PNGWriter::writeIDAT(T const& image)
|
||||
{
|
||||
// Write IDAT chunk.
|
||||
size_t IDAT = startChunk(IDAT_tpl, 8);
|
||||
mz_uint8 filter_type = 0;
|
||||
tdefl_status status;
|
||||
|
||||
int bytes_per_pixel = sizeof(typename T::pixel_type);
|
||||
int stride = image.width() * bytes_per_pixel;
|
||||
|
||||
for (unsigned int y = 0; y < image.height(); y++)
|
||||
{
|
||||
// Write filter_type
|
||||
status = tdefl_compress_buffer(compressor, &filter_type, 1, TDEFL_NO_FLUSH);
|
||||
if (status != TDEFL_STATUS_OKAY)
|
||||
{
|
||||
throw std::runtime_error("failed to compress image");
|
||||
}
|
||||
|
||||
// Write scanline
|
||||
status = tdefl_compress_buffer(compressor, (mz_uint8 *)image.getRow(y), stride, TDEFL_NO_FLUSH);
|
||||
if (status != TDEFL_STATUS_OKAY)
|
||||
{
|
||||
throw std::runtime_error("failed to compress image");
|
||||
}
|
||||
}
|
||||
|
||||
status = tdefl_compress_buffer(compressor, NULL, 0, TDEFL_FINISH);
|
||||
if (status != TDEFL_STATUS_DONE)
|
||||
{
|
||||
throw std::runtime_error("failed to compress image");
|
||||
}
|
||||
|
||||
finishChunk(IDAT);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PNGWriter::writeIDATStripAlpha(T const& image) {
|
||||
// Write IDAT chunk.
|
||||
size_t IDAT = startChunk(IDAT_tpl, 8);
|
||||
mz_uint8 filter_type = 0;
|
||||
tdefl_status status;
|
||||
|
||||
size_t stride = image.width() * 3;
|
||||
size_t i, j;
|
||||
mz_uint8 *scanline = (mz_uint8 *)MZ_MALLOC(stride);
|
||||
|
||||
for (unsigned int y = 0; y < image.height(); y++) {
|
||||
// Write filter_type
|
||||
status = tdefl_compress_buffer(compressor, &filter_type, 1, TDEFL_NO_FLUSH);
|
||||
if (status != TDEFL_STATUS_OKAY)
|
||||
{
|
||||
MZ_FREE(scanline);
|
||||
throw std::runtime_error("failed to compress image");
|
||||
}
|
||||
|
||||
// Strip alpha bytes from scanline
|
||||
mz_uint8 *row = (mz_uint8 *)image.getRow(y);
|
||||
for (i = 0, j = 0; j < stride; i += 4, j += 3) {
|
||||
scanline[j] = row[i];
|
||||
scanline[j+1] = row[i+1];
|
||||
scanline[j+2] = row[i+2];
|
||||
}
|
||||
|
||||
// Write scanline
|
||||
status = tdefl_compress_buffer(compressor, scanline, stride, TDEFL_NO_FLUSH);
|
||||
if (status != TDEFL_STATUS_OKAY) {
|
||||
MZ_FREE(scanline);
|
||||
throw std::runtime_error("failed to compress image");
|
||||
}
|
||||
}
|
||||
|
||||
MZ_FREE(scanline);
|
||||
|
||||
status = tdefl_compress_buffer(compressor, NULL, 0, TDEFL_FINISH);
|
||||
if (status != TDEFL_STATUS_DONE) throw std::runtime_error("failed to compress image");
|
||||
|
||||
finishChunk(IDAT);
|
||||
}
|
||||
|
||||
void PNGWriter::writeIEND()
|
||||
{
|
||||
// Write IEND chunk.
|
||||
size_t IEND = startChunk(IEND_tpl, 8);
|
||||
finishChunk(IEND);
|
||||
}
|
||||
|
||||
void PNGWriter::toStream(std::ostream& stream)
|
||||
{
|
||||
stream.write((char *)buffer->m_pBuf, buffer->m_size);
|
||||
}
|
||||
|
||||
const mz_uint8 PNGWriter::preamble[] = {
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a
|
||||
};
|
||||
|
||||
const mz_uint8 PNGWriter::IHDR_tpl[] = {
|
||||
0x00, 0x00, 0x00, 0x0D, // chunk length
|
||||
'I', 'H', 'D', 'R', // "IHDR"
|
||||
0x00, 0x00, 0x00, 0x00, // image width (4 bytes)
|
||||
0x00, 0x00, 0x00, 0x00, // image height (4 bytes)
|
||||
0x00, // bit depth (1 byte)
|
||||
0x00, // color type (1 byte)
|
||||
0x00, // compression method (1 byte), has to be 0
|
||||
0x00, // filter method (1 byte)
|
||||
0x00 // interlace method (1 byte)
|
||||
};
|
||||
|
||||
const mz_uint8 PNGWriter::PLTE_tpl[] = {
|
||||
0x00, 0x00, 0x00, 0x00, // chunk length
|
||||
'P', 'L', 'T', 'E' // "IDAT"
|
||||
};
|
||||
|
||||
const mz_uint8 PNGWriter::tRNS_tpl[] = {
|
||||
0x00, 0x00, 0x00, 0x00, // chunk length
|
||||
't', 'R', 'N', 'S' // "IDAT"
|
||||
};
|
||||
|
||||
const mz_uint8 PNGWriter::IDAT_tpl[] = {
|
||||
0x00, 0x00, 0x00, 0x00, // chunk length
|
||||
'I', 'D', 'A', 'T' // "IDAT"
|
||||
};
|
||||
|
||||
const mz_uint8 PNGWriter::IEND_tpl[] = {
|
||||
0x00, 0x00, 0x00, 0x00, // chunk length
|
||||
'I', 'E', 'N', 'D' // "IEND"
|
||||
};
|
||||
|
||||
template void PNGWriter::writeIDAT<image_data_8>(image_data_8 const& image);
|
||||
template void PNGWriter::writeIDAT<image_view<image_data_8> >(image_view<image_data_8> const& image);
|
||||
template void PNGWriter::writeIDAT<image_data_32>(image_data_32 const& image);
|
||||
template void PNGWriter::writeIDAT<image_view<image_data_32> >(image_view<image_data_32> const& image);
|
||||
template void PNGWriter::writeIDATStripAlpha<image_data_32>(image_data_32 const& image);
|
||||
template void PNGWriter::writeIDATStripAlpha<image_view<image_data_32> >(image_view<image_data_32> const& image);
|
||||
|
||||
}}
|
||||
|
|
@ -75,9 +75,9 @@ bool rgba_palette::valid() const
|
|||
}
|
||||
|
||||
// return color index in returned earlier palette
|
||||
unsigned rgba_palette::quantize(rgba const& c) const
|
||||
unsigned char rgba_palette::quantize(rgba const& c) const
|
||||
{
|
||||
unsigned index = 0;
|
||||
unsigned char index = 0;
|
||||
if (colors_ == 1) return index;
|
||||
|
||||
rgba_hash_table::iterator it = color_hashmap_.find(c);
|
||||
|
|
|
@ -98,6 +98,10 @@ public:
|
|||
{
|
||||
set_attr( sym_node, "rasterizer", sym.get_rasterizer() );
|
||||
}
|
||||
if ( sym.get_offset() != dfl.get_offset() || explicit_defaults_ )
|
||||
{
|
||||
set_attr( sym_node, "offset", sym.get_offset() );
|
||||
}
|
||||
serialize_symbolizer_base(sym_node, sym);
|
||||
}
|
||||
|
||||
|
@ -319,6 +323,10 @@ public:
|
|||
{
|
||||
set_attr( sym_node, "placement", sym.get_marker_placement() );
|
||||
}
|
||||
if ( sym.get_marker_multi_policy() != dfl.get_marker_multi_policy() || explicit_defaults_ )
|
||||
{
|
||||
set_attr( sym_node, "multi-policy", sym.get_marker_multi_policy() );
|
||||
}
|
||||
if (sym.get_image_transform())
|
||||
{
|
||||
std::string tr_str = sym.get_image_transform_string();
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace mapnik
|
|||
{
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(building_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// nothing yet.
|
||||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(building_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace mapnik
|
|||
{
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(line_pattern_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// nothing yet.
|
||||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(line_pattern_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace mapnik
|
|||
*/
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(line_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
path_attributes_.set_stroke_color(sym.get_stroke().get_color());
|
||||
|
@ -43,6 +43,6 @@ void svg_renderer<T>::process(line_symbolizer const& sym,
|
|||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(line_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace mapnik
|
|||
{
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(markers_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// nothing yet.
|
||||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(markers_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace mapnik
|
|||
{
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(point_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// nothing yet.
|
||||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(point_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace mapnik
|
|||
{
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(polygon_pattern_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// nothing yet.
|
||||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(polygon_pattern_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace mapnik
|
|||
*/
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(polygon_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
path_attributes_.set_fill_color(sym.get_fill());
|
||||
|
@ -38,6 +38,6 @@ void svg_renderer<T>::process(polygon_symbolizer const& sym,
|
|||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(polygon_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace mapnik
|
|||
{
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(raster_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// nothing yet.
|
||||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(raster_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace mapnik
|
|||
{
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(shield_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// nothing yet.
|
||||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(shield_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -27,11 +27,10 @@ namespace mapnik {
|
|||
|
||||
template <typename OutputIterator>
|
||||
bool svg_renderer<OutputIterator>::process(rule::symbolizers const& syms,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// svg renderer supports processing of multiple symbolizers.
|
||||
|
||||
typedef coord_transform<CoordTransform, geometry_type> path_type;
|
||||
|
||||
// process each symbolizer to collect its (path) information.
|
||||
|
@ -45,8 +44,8 @@ bool svg_renderer<OutputIterator>::process(rule::symbolizers const& syms,
|
|||
// generate path output for each geometry of the current feature.
|
||||
for(unsigned i=0; i<feature.num_geometries(); ++i)
|
||||
{
|
||||
geometry_type const& geom = feature.get_geometry(i);
|
||||
if(geom.size() > 1)
|
||||
geometry_type & geom = feature.get_geometry(i);
|
||||
if(geom.size() > 0)
|
||||
{
|
||||
path_type path(t_, geom, prj_trans);
|
||||
generator_.generate_path(path, path_attributes_);
|
||||
|
@ -61,7 +60,7 @@ bool svg_renderer<OutputIterator>::process(rule::symbolizers const& syms,
|
|||
};
|
||||
|
||||
template bool svg_renderer<std::ostream_iterator<char> >::process(rule::symbolizers const& syms,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace mapnik
|
|||
{
|
||||
template <typename T>
|
||||
void svg_renderer<T>::process(text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans)
|
||||
{
|
||||
// nothing yet.
|
||||
}
|
||||
|
||||
template void svg_renderer<std::ostream_iterator<char> >::process(text_symbolizer const& sym,
|
||||
Feature const& feature,
|
||||
mapnik::feature_impl & feature,
|
||||
proj_transform const& prj_trans);
|
||||
}
|
||||
|
|
|
@ -65,17 +65,5 @@ namespace mapnik { namespace svg {
|
|||
karma::generate(output_iterator_, lit("<rect ") << attributes_grammar << lit("/>\n"), rect_attributes);
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
void svg_generator<OutputIterator>::generate_path(path_type const& path, path_output_attributes const& path_attributes)
|
||||
{
|
||||
path_data_grammar data_grammar(path);
|
||||
path_attributes_grammar attributes_grammar;
|
||||
path_dash_array_grammar dash_array_grammar;
|
||||
|
||||
karma::generate(output_iterator_, lit("<path ") << data_grammar, path);
|
||||
karma::generate(output_iterator_, lit(" ") << dash_array_grammar, path_attributes.stroke_dasharray());
|
||||
karma::generate(output_iterator_, lit(" ") << attributes_grammar << lit("/>\n"), path_attributes);
|
||||
}
|
||||
|
||||
template class svg_generator<std::ostream_iterator<char> >;
|
||||
}}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*****************************************************************************/
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/svg/svg_output_attributes.hpp>
|
||||
#include <mapnik/svg/output/svg_output_attributes.hpp>
|
||||
|
||||
namespace mapnik { namespace svg {
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ void svg_renderer<T>::end_map_processing(Map const& map)
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void svg_renderer<T>::start_layer_processing(layer const& lay)
|
||||
void svg_renderer<T>::start_layer_processing(layer const& lay, box2d<double> const& query_extent)
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(svg_renderer) << "svg_renderer: Start layer processing=" << lay.name();
|
||||
}
|
||||
|
|
|
@ -90,9 +90,13 @@ transform_type const& symbolizer_base::get_transform() const
|
|||
std::string symbolizer_base::get_transform_string() const
|
||||
{
|
||||
if (affine_transform_)
|
||||
{
|
||||
return transform_processor_type::to_string(*affine_transform_);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
void symbolizer_base::set_clip(bool clip)
|
||||
|
@ -190,9 +194,13 @@ transform_type const& symbolizer_with_image::get_image_transform() const
|
|||
std::string symbolizer_with_image::get_image_transform_string() const
|
||||
{
|
||||
if (image_transform_)
|
||||
{
|
||||
return transform_processor_type::to_string(*image_transform_);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace mapnik
|
||||
|
|
|
@ -472,6 +472,7 @@ compile_get_attr(std::string);
|
|||
compile_get_attr(filter_mode_e);
|
||||
compile_get_attr(point_placement_e);
|
||||
compile_get_attr(marker_placement_e);
|
||||
compile_get_attr(marker_multi_policy_e);
|
||||
compile_get_attr(pattern_alignment_e);
|
||||
compile_get_attr(line_rasterizer_e);
|
||||
compile_get_attr(colorizer_mode);
|
||||
|
|
|
@ -31,6 +31,9 @@ int main( int, char*[] )
|
|||
BOOST_TEST( x == 25 );
|
||||
BOOST_TEST( y == 25 );
|
||||
|
||||
// TODO - centroid and interior should be equal but they appear not to be (check largest)
|
||||
// MULTIPOLYGON(((-52 40,-60 32,-68 40,-60 48,-52 40)),((-60 50,-80 30,-100 49.9999999999999,-80.0000000000001 70,-60 50)),((-52 60,-60 52,-68 60,-60 68,-52 60)))
|
||||
|
||||
if (!::boost::detail::test_errors()) {
|
||||
std::clog << "C++ label algorithms: \x1b[1;32m✓ \x1b[0m\n";
|
||||
#if BOOST_VERSION >= 104600
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <fstream>
|
||||
#include <iterator>
|
||||
|
||||
namespace filesystem = boost::filesystem;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
/*
|
||||
* This test case tests the generation of an SVG document
|
||||
|
@ -57,10 +57,10 @@ BOOST_AUTO_TEST_CASE(file_output_test_case)
|
|||
|
||||
output_stream.close();
|
||||
|
||||
filesystem::path output_filename_path =
|
||||
filesystem::system_complete(filesystem::path(".")) / filesystem::path(output_filename);
|
||||
fs::path output_filename_path =
|
||||
fs::system_complete(fs::path(".")) / fs::path(output_filename);
|
||||
|
||||
BOOST_CHECK_MESSAGE(filesystem::exists(output_filename_path), "File '"+output_filename_path.string()+"' was created.");
|
||||
BOOST_CHECK_MESSAGE(fs::exists(output_filename_path), "File '"+output_filename_path.string()+"' was created.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <fstream>
|
||||
#include <iterator>
|
||||
|
||||
namespace filesystem = boost::filesystem;
|
||||
namespace fs = boost::filesystem;
|
||||
using namespace mapnik;
|
||||
|
||||
void prepare_map(Map& m)
|
||||
|
@ -205,10 +205,10 @@ void render_to_file(Map const& m, const std::string output_filename)
|
|||
|
||||
output_stream.close();
|
||||
|
||||
filesystem::path output_filename_path =
|
||||
filesystem::system_complete(filesystem::path(".")) / filesystem::path(output_filename);
|
||||
fs::path output_filename_path =
|
||||
fs::system_complete(fs::path(".")) / fs::path(output_filename);
|
||||
|
||||
BOOST_CHECK_MESSAGE(filesystem::exists(output_filename_path),
|
||||
BOOST_CHECK_MESSAGE(fs::exists(output_filename_path),
|
||||
"File '"+output_filename_path.string()+"' was created.");
|
||||
}
|
||||
else
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<Layer name="lay" srs="+proj=longlat +ellps=airy +datum=OSGB36 +no_defs">
|
||||
<StyleName>test</StyleName>
|
||||
<Datasource base="shp">
|
||||
<Datasource>
|
||||
<Parameter name="type">shape</Parameter>
|
||||
<Parameter name="file">../../data/shp/poly.shp</Parameter>
|
||||
</Datasource>
|
||||
|
|
BIN
tests/data/images/12_654_1580.png
Normal file
BIN
tests/data/images/12_654_1580.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 156 KiB |
12
tests/data/json/null_feature.json
Normal file
12
tests/data/json/null_feature.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{ "type": "FeatureCollection",
|
||||
"features": [
|
||||
{ "type": "Feature",
|
||||
"geometry": {"type": "Point"},
|
||||
"properties": {"feat_id": 0}
|
||||
},
|
||||
{ "type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates":[0,0]},
|
||||
"properties": {"feat_id": 1}
|
||||
}
|
||||
]
|
||||
}
|
63
tests/python_tests/buffer_clear_test.py
Normal file
63
tests/python_tests/buffer_clear_test.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
import sys
|
||||
import os, mapnik
|
||||
from timeit import Timer, time
|
||||
from nose.tools import *
|
||||
from utilities import execution_path
|
||||
|
||||
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_clearing_image_data():
|
||||
im = mapnik.Image(256,256)
|
||||
# make sure it equals itself
|
||||
bytes = im.tostring()
|
||||
eq_(im.tostring(),bytes)
|
||||
# set background, then clear
|
||||
im.background = mapnik.Color('green')
|
||||
eq_(im.tostring()!=bytes,True)
|
||||
# clear image, should now equal original
|
||||
im.clear()
|
||||
eq_(im.tostring(),bytes)
|
||||
|
||||
def make_map():
|
||||
ds = mapnik.MemoryDatasource()
|
||||
context = mapnik.Context()
|
||||
context.push('Name')
|
||||
pixel_key = 1
|
||||
f = mapnik.Feature(context,pixel_key)
|
||||
f['Name'] = str(pixel_key)
|
||||
f.add_geometries_from_wkt('POLYGON ((0 0, 0 256, 256 256, 256 0, 0 0))')
|
||||
ds.add_feature(f)
|
||||
s = mapnik.Style()
|
||||
r = mapnik.Rule()
|
||||
symb = mapnik.PolygonSymbolizer()
|
||||
r.symbols.append(symb)
|
||||
s.rules.append(r)
|
||||
lyr = mapnik.Layer('Places')
|
||||
lyr.datasource = ds
|
||||
lyr.styles.append('places_labels')
|
||||
width,height = 256,256
|
||||
m = mapnik.Map(width,height)
|
||||
m.append_style('places_labels',s)
|
||||
m.layers.append(lyr)
|
||||
m.zoom_all()
|
||||
return m
|
||||
|
||||
def test_clearing_grid_data():
|
||||
g = mapnik.Grid(256,256)
|
||||
utf = g.encode()
|
||||
# make sure it equals itself
|
||||
eq_(g.encode(),utf)
|
||||
m = make_map()
|
||||
mapnik.render_layer(m,g,layer=0,fields=['__id__','Name'])
|
||||
eq_(g.encode()!=utf,True)
|
||||
# clear grid, should now match original
|
||||
g.clear()
|
||||
eq_(g.encode(),utf)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup()
|
||||
[eval(run)() for run in dir() if 'test_' in run]
|
|
@ -149,47 +149,48 @@ def test_pre_multiply_status_of_map2():
|
|||
mapnik.render(m,im)
|
||||
eq_(validate_pixels_are_not_premultiplied(im),True)
|
||||
|
||||
def test_style_level_comp_op():
|
||||
m = mapnik.Map(256, 256)
|
||||
mapnik.load_map(m, '../data/good_maps/style_level_comp_op.xml')
|
||||
m.zoom_all()
|
||||
successes = []
|
||||
fails = []
|
||||
for name in mapnik.CompositeOp.names:
|
||||
# find_style returns a copy of the style object
|
||||
style_markers = m.find_style("markers")
|
||||
style_markers.comp_op = getattr(mapnik.CompositeOp, name)
|
||||
# replace the original style with the modified one
|
||||
replace_style(m, "markers", style_markers)
|
||||
im = mapnik.Image(m.width, m.height)
|
||||
mapnik.render(m, im)
|
||||
actual = '/tmp/mapnik-style-comp-op-' + name + '.png'
|
||||
expected = 'images/style-comp-op/' + name + '.png'
|
||||
im.save(actual)
|
||||
if not os.path.exists(expected):
|
||||
print 'generating expected test image: %s' % expected
|
||||
im.save(expected)
|
||||
expected_im = mapnik.Image.open(expected)
|
||||
# compare them
|
||||
if im.tostring() == expected_im.tostring():
|
||||
successes.append(name)
|
||||
else:
|
||||
fails.append('failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
|
||||
fail_im = side_by_side_image(expected_im, im)
|
||||
fail_im.save('/tmp/mapnik-style-comp-op-' + name + '.fail.png')
|
||||
eq_(len(fails), 0, '\n'+'\n'.join(fails))
|
||||
if 'shape' in mapnik.DatasourceCache.plugin_names():
|
||||
def test_style_level_comp_op():
|
||||
m = mapnik.Map(256, 256)
|
||||
mapnik.load_map(m, '../data/good_maps/style_level_comp_op.xml')
|
||||
m.zoom_all()
|
||||
successes = []
|
||||
fails = []
|
||||
for name in mapnik.CompositeOp.names:
|
||||
# find_style returns a copy of the style object
|
||||
style_markers = m.find_style("markers")
|
||||
style_markers.comp_op = getattr(mapnik.CompositeOp, name)
|
||||
# replace the original style with the modified one
|
||||
replace_style(m, "markers", style_markers)
|
||||
im = mapnik.Image(m.width, m.height)
|
||||
mapnik.render(m, im)
|
||||
actual = '/tmp/mapnik-style-comp-op-' + name + '.png'
|
||||
expected = 'images/style-comp-op/' + name + '.png'
|
||||
im.save(actual)
|
||||
if not os.path.exists(expected):
|
||||
print 'generating expected test image: %s' % expected
|
||||
im.save(expected)
|
||||
expected_im = mapnik.Image.open(expected)
|
||||
# compare them
|
||||
if im.tostring() == expected_im.tostring():
|
||||
successes.append(name)
|
||||
else:
|
||||
fails.append('failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
|
||||
fail_im = side_by_side_image(expected_im, im)
|
||||
fail_im.save('/tmp/mapnik-style-comp-op-' + name + '.fail.png')
|
||||
eq_(len(fails), 0, '\n'+'\n'.join(fails))
|
||||
|
||||
def test_style_level_opacity():
|
||||
m = mapnik.Map(512,512)
|
||||
mapnik.load_map(m,'../data/good_maps/style_level_opacity_and_blur.xml')
|
||||
m.zoom_all()
|
||||
im = mapnik.Image(512,512)
|
||||
mapnik.render(m,im)
|
||||
actual = '/tmp/mapnik-style-level-opacity.png'
|
||||
expected = 'images/support/mapnik-style-level-opacity.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_style_level_opacity():
|
||||
m = mapnik.Map(512,512)
|
||||
mapnik.load_map(m,'../data/good_maps/style_level_opacity_and_blur.xml')
|
||||
m.zoom_all()
|
||||
im = mapnik.Image(512,512)
|
||||
mapnik.render(m,im)
|
||||
actual = '/tmp/mapnik-style-level-opacity.png'
|
||||
expected = 'images/support/mapnik-style-level-opacity.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_rounding_and_color_expectations():
|
||||
m = mapnik.Map(1,1)
|
||||
|
|
|
@ -157,12 +157,17 @@ def test_regex_replace():
|
|||
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
|
||||
eq_(expr.evaluate(f),'t e s t')
|
||||
|
||||
def test_unicode_regex_replace_to_str():
|
||||
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
|
||||
eq_(str(expr),"[name].replace('(\B)|( )','$1 ')")
|
||||
|
||||
def test_unicode_regex_replace():
|
||||
context = mapnik.Context()
|
||||
context.push('name')
|
||||
f = mapnik.Feature(context,0)
|
||||
f["name"] = 'Québec'
|
||||
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
|
||||
# will fail if -DBOOST_REGEX_HAS_ICU is not defined
|
||||
eq_(expr.evaluate(f), u'Q u é b e c')
|
||||
|
||||
def test_float_precision():
|
||||
|
|
|
@ -18,14 +18,23 @@ combinations = ['png',
|
|||
'png8:m=h',
|
||||
'png8:m=o:t=0',
|
||||
'png8:m=o:t=1',
|
||||
'png8:m=o:t=2',
|
||||
'png8:m=h:t=0',
|
||||
'png8:m=h:t=1',
|
||||
'png8:m=h:t=2',
|
||||
'png:z=1',
|
||||
'png8:z=1',
|
||||
'png8:z=1:m=o',
|
||||
'png8:z=1:m=h',
|
||||
'png8:z=1:c=50',
|
||||
'png8:z=1:c=1',
|
||||
'png8:z=1:c=24',
|
||||
'png8:z=1:c=64',
|
||||
'png8:z=1:c=128',
|
||||
'png8:z=1:c=200',
|
||||
'png8:z=1:c=255',
|
||||
'png8:z=9:c=64',
|
||||
'png8:z=9:c=128',
|
||||
'png8:z=9:c=200',
|
||||
'png8:z=1:c=50:m=h',
|
||||
'png8:z=1:c=1:m=o',
|
||||
'png8:z=1:c=1:m=o:s=filtered',
|
||||
|
@ -36,10 +45,18 @@ combinations = ['png',
|
|||
'png:m=h;g=1.0',
|
||||
]
|
||||
|
||||
tiles = [
|
||||
'blank',
|
||||
'solid',
|
||||
'many_colors',
|
||||
'aerial_24'
|
||||
]
|
||||
|
||||
iterations = 10
|
||||
|
||||
def do_encoding():
|
||||
|
||||
image = None
|
||||
iterations = 10
|
||||
|
||||
results = {}
|
||||
sortable = {}
|
||||
|
@ -53,47 +70,55 @@ def do_encoding():
|
|||
min_ = min(set)*1000
|
||||
avg = (sum(set)/len(set))*1000
|
||||
name = func.__name__ + ' ' + format
|
||||
results[name] = [avg,min_,elapsed*1000,name]
|
||||
sortable[name] = [avg]
|
||||
results[name] = [min_,avg,elapsed*1000,name,len(func())]
|
||||
sortable[name] = [min_]
|
||||
|
||||
def blank():
|
||||
eval('image.tostring("%s")' % c)
|
||||
blank_im = mapnik.Image(512,512)
|
||||
if 'blank' in tiles:
|
||||
def blank():
|
||||
return eval('image.tostring("%s")' % c)
|
||||
blank_im = mapnik.Image(512,512)
|
||||
for c in combinations:
|
||||
t = Timer(blank)
|
||||
run(blank,blank_im,c,t)
|
||||
|
||||
for c in combinations:
|
||||
t = Timer(blank)
|
||||
run(blank,blank_im,c,t)
|
||||
if 'solid' in tiles:
|
||||
def solid():
|
||||
return eval('image.tostring("%s")' % c)
|
||||
solid_im = mapnik.Image(512,512)
|
||||
solid_im.background = mapnik.Color("#f2efe9")
|
||||
for c in combinations:
|
||||
t = Timer(solid)
|
||||
run(solid,solid_im,c,t)
|
||||
|
||||
def solid():
|
||||
eval('image.tostring("%s")' % c)
|
||||
solid_im = mapnik.Image(512,512)
|
||||
solid_im.background = mapnik.Color("#f2efe9")
|
||||
if 'many_colors' in tiles:
|
||||
def many_colors():
|
||||
return eval('image.tostring("%s")' % c)
|
||||
# lots of colors: http://tile.osm.org/13/4194/2747.png
|
||||
many_colors_im = mapnik.Image.open('../data/images/13_4194_2747.png')
|
||||
for c in combinations:
|
||||
t = Timer(many_colors)
|
||||
run(many_colors,many_colors_im,c,t)
|
||||
|
||||
for c in combinations:
|
||||
t = Timer(solid)
|
||||
run(solid,solid_im,c,t)
|
||||
|
||||
def many_colors():
|
||||
eval('image.tostring("%s")' % c)
|
||||
# lots of colors: http://tile.osm.org/13/4194/2747.png
|
||||
many_colors_im = mapnik.Image.open('../data/images/13_4194_2747.png')
|
||||
|
||||
for c in combinations:
|
||||
t = Timer(many_colors)
|
||||
run(many_colors,many_colors_im,c,t)
|
||||
if 'aerial_24' in tiles:
|
||||
def aerial_24():
|
||||
return eval('image.tostring("%s")' % c)
|
||||
aerial_24_im = mapnik.Image.open('../data/images/12_654_1580.png')
|
||||
for c in combinations:
|
||||
t = Timer(aerial_24)
|
||||
run(aerial_24,aerial_24_im,c,t)
|
||||
|
||||
for key, value in sorted(sortable.iteritems(), key=lambda (k,v): (v,k)):
|
||||
s = results[key]
|
||||
avg = str(s[0])[:6]
|
||||
min_ = str(s[1])[:6]
|
||||
min_ = str(s[0])[:6]
|
||||
avg = str(s[1])[:6]
|
||||
elapsed = str(s[2])[:6]
|
||||
percent_reduction = s[4]
|
||||
name = s[3]
|
||||
print 'avg: %sms | min: %sms | total: %sms <-- %s' % (min_,avg,elapsed,name)
|
||||
size = s[4]
|
||||
print 'min: %sms | avg: %sms | total: %sms | len: %s <-- %s' % (min_,avg,elapsed,size,name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup()
|
||||
do_encoding()
|
||||
for t in dir():
|
||||
if 'test_' in t:
|
||||
eval(t)()
|
||||
[eval(run)() for run in dir() if 'test_' in run]
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue