-
-
Save springmeyer/2778d7c64b301c9e2aa5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/include/mapnik/color.hpp b/include/mapnik/color.hpp | |
index f21ef76..b6c45cb 100644 | |
--- a/include/mapnik/color.hpp | |
+++ b/include/mapnik/color.hpp | |
@@ -28,6 +28,7 @@ | |
#include <mapnik/global.hpp> | |
//boost | |
+#include <boost/cstdint.hpp> | |
#include <boost/operators.hpp> | |
// stl | |
@@ -71,6 +72,7 @@ public: | |
std::string to_string() const; | |
std::string to_hex_string() const; | |
+ std::string to_hex_string_no_alpha() const; | |
void premultiply(); | |
void demultiply(); | |
diff --git a/include/mapnik/svg/output/svg_generator.hpp b/include/mapnik/svg/output/svg_generator.hpp | |
index 656f650..4250fb3 100644 | |
--- a/include/mapnik/svg/output/svg_generator.hpp | |
+++ b/include/mapnik/svg/output/svg_generator.hpp | |
@@ -57,6 +57,10 @@ namespace mapnik { namespace svg { | |
typedef svg::svg_rect_attributes_grammar<OutputIterator> rect_attributes_grammar; | |
typedef svg::svg_path_attributes_grammar<OutputIterator> path_attributes_grammar; | |
typedef svg::svg_path_dash_array_grammar<OutputIterator> path_dash_array_grammar; | |
+ typedef svg::svg_text_attributes_grammar<OutputIterator> text_attributes_grammar; | |
+ typedef svg::svg_text_fill_attributes_grammar<OutputIterator> text_fill_attributes_grammar; | |
+ typedef svg::svg_text_stroke_attributes_grammar<OutputIterator> text_stroke_attributes_grammar; | |
+ | |
public: | |
explicit svg_generator(OutputIterator& output_iterator); | |
@@ -80,7 +84,39 @@ namespace mapnik { namespace svg { | |
karma::generate(output_iterator_, lit(" ") << dash_array_grammar, path_attributes.stroke_dasharray()); | |
karma::generate(output_iterator_, lit(" ") << attributes_grammar << lit("/>\n"), path_attributes); | |
} | |
+ template <typename PathType> | |
+ void generate_text_on_path(value_unicode_string const& str, text_output_attributes_fill const &text_attr, | |
+ text_output_attributes_stroke const &text_halo_attr, PathType const &path, | |
+ path_output_attributes const &attr) | |
+ { | |
+ // assign some id to the path | |
+ int path_id = rand(); | |
+ | |
+ // create path definition | |
+ karma::generate(output_iterator_, lit("<defs>") << lit("<path id=\"p") << int_ << lit("\" "), path_id); | |
+ | |
+ util::svg_generator<OutputIterator,PathType> svg_path_grammer; | |
+ karma::generate(output_iterator_, svg_path_grammer, path); | |
+ | |
+ path_attributes_grammar attributes_grammar; | |
+ karma::generate(output_iterator_, lit(" ") << attributes_grammar << lit("/>\n</defs>\n"), attr); | |
+ // convert text to utf as this is the default xml encoding | |
+ std::string utf8; | |
+ to_utf8(str, utf8); | |
+ | |
+ // default value of stroke in svg is 1, so do not output a halo if the radius is 1 | |
+ text_stroke_attributes_grammar halo_grammar; | |
+ if(text_halo_attr.halo_radius() != 1.0) { | |
+ karma::generate(output_iterator_, lit("<text ") << halo_grammar << ">", text_halo_attr); | |
+ karma::generate(output_iterator_, lit("\n<textPath xlink:href=\"#p") << int_ << lit("\">\n"), path_id); | |
+ karma::generate(output_iterator_, utf8 << lit("\n</textPath>\n</text>\n")); | |
+ } | |
+ text_fill_attributes_grammar text_grammar; | |
+ karma::generate(output_iterator_, lit("<text ") << text_grammar << ">", text_attr); | |
+ karma::generate(output_iterator_, lit("\n<textPath xlink:href=\"#p") << int_ << lit("\">\n"), path_id); | |
+ karma::generate(output_iterator_, utf8 << lit("\n</textPath>\n</text>\n")); | |
+ } | |
private: | |
OutputIterator& output_iterator_; | |
}; | |
diff --git a/include/mapnik/svg/output/svg_output_attributes.hpp b/include/mapnik/svg/output/svg_output_attributes.hpp | |
index eb1e8b6..eb3bf14 100644 | |
--- a/include/mapnik/svg/output/svg_output_attributes.hpp | |
+++ b/include/mapnik/svg/output/svg_output_attributes.hpp | |
@@ -26,6 +26,7 @@ | |
// mapnik | |
#include <mapnik/color.hpp> | |
#include <mapnik/symbolizer.hpp> | |
+#include <mapnik/text/text_properties.hpp> | |
// stl | |
#include <string> | |
@@ -196,6 +197,123 @@ namespace mapnik { namespace svg { | |
double svg_version_; | |
std::string svg_namespace_url_; | |
}; | |
+ | |
+ /*! | |
+ * \brief The text_output_attributes struct | |
+ * This structure encapsulates the values needed to | |
+ * generate an svg (root) tag. | |
+ * | |
+ * The values are stored using the variable types that | |
+ * are required for output generation, but the interface | |
+ * is written with the original types. "set" methods | |
+ * perform the necessary conversions (i.e. from color to | |
+ * hex string | |
+ */ | |
+ struct text_output_attributes | |
+ { | |
+ text_output_attributes() | |
+ : text_ratio_(0), | |
+ text_size_(10), | |
+ char_spacing_(0), | |
+ transform_("none") | |
+ {;} | |
+ | |
+ // general layout options | |
+ void set_text_ratio(const double ratio); | |
+ // character formatting options | |
+ void set_face_name(const std::string &name); | |
+ void set_fontset(const std::string &name); | |
+ void set_text_size(const double size); | |
+ void set_char_spacing(const double &space); | |
+ void set_text_transform(const text_transform_e &trans); | |
+ | |
+ double text_ratio() const; | |
+ std::string face_name() const; | |
+ std::string fontset() const; | |
+ double text_size() const; | |
+ double halo_radius() const; | |
+ double char_spacing() const; | |
+ std::string transform() const; | |
+ | |
+ // reset to default values | |
+ void reset(); | |
+ | |
+ // general layout options | |
+ // - text-ratio | |
+ // character formatting options | |
+ // - face-name | |
+ // - fontset-name | |
+ // - size | |
+ // - character spacing | |
+ // - text-transform | |
+ double text_ratio_; | |
+ std::string face_name_; | |
+ std::string fontset_; | |
+ double text_size_; | |
+ double char_spacing_; | |
+ std::string transform_; | |
+ }; | |
+ | |
+ struct text_output_attributes_stroke : public text_output_attributes { | |
+ text_output_attributes_stroke() | |
+ : text_output_attributes(), | |
+ halo_fill_("#FFFFFF"), | |
+ stroke_opacity_(1.0), | |
+ halo_radius_(0) | |
+ {;} | |
+ | |
+ // character formatting options | |
+ void set_halo_fill(const color &fill); | |
+ void set_halo_radius(const double &radius); | |
+ | |
+ std::string halo_fill() const; | |
+ double stroke_opacity() const; | |
+ double halo_radius() const; | |
+ | |
+ // reset to default values | |
+ void reset(); | |
+ | |
+ // character formatting options | |
+ // - hallo-fill | |
+ // - halo-radius | |
+ std::string halo_fill_; | |
+ double stroke_opacity_; | |
+ double halo_radius_; | |
+ }; | |
+ | |
+ /*! | |
+ * \brief The text_output_attributes struct | |
+ * This structure encapsulates the values needed to | |
+ * generate an svg (root) tag. | |
+ * | |
+ * The values are stored using the variable types that | |
+ * are required for output generation, but the interface | |
+ * is written with the original types. "set" methods | |
+ * perform the necessary conversions (i.e. from color to | |
+ * hex string | |
+ */ | |
+ struct text_output_attributes_fill : public text_output_attributes | |
+ { | |
+ text_output_attributes_fill() | |
+ : text_output_attributes(), | |
+ fill_("#000000"), | |
+ fill_opacity_(1.0) | |
+ {;} | |
+ | |
+ // character formatting options | |
+ void set_fill(const color &fill); | |
+ | |
+ std::string fill() const; | |
+ double fill_opacity() const; | |
+ | |
+ // reset to default values | |
+ void reset(); | |
+ | |
+ // character formatting options | |
+ // - fill | |
+ std::string fill_; | |
+ double fill_opacity_; | |
+ }; | |
}} | |
#endif // MAPNIK_SVG_OUTPUT_ATTRIBUTES | |
diff --git a/include/mapnik/svg/output/svg_output_grammars.hpp b/include/mapnik/svg/output/svg_output_grammars.hpp | |
index 802b803..28b772c 100644 | |
--- a/include/mapnik/svg/output/svg_output_grammars.hpp | |
+++ b/include/mapnik/svg/output/svg_output_grammars.hpp | |
@@ -31,6 +31,9 @@ namespace mapnik { namespace svg { | |
struct path_output_attributes; | |
struct rect_output_attributes; | |
struct root_output_attributes; | |
+ struct text_output_attributes; | |
+ struct text_output_attributes_fill; | |
+ struct text_output_attributes_stroke; | |
} } | |
// boost | |
@@ -88,6 +91,49 @@ BOOST_FUSION_ADAPT_STRUCT( | |
(std::string, svg_namespace_url_) | |
) | |
+/*! | |
+ * mapnik::svg::text_output_attributes is adapted as a fusion sequence | |
+ * in order to be used directly by the text_output_attributes (below). | |
+ */ | |
+BOOST_FUSION_ADAPT_STRUCT( | |
+ mapnik::svg::text_output_attributes, | |
+ (std::string, fontset_) | |
+ (double, text_size_) | |
+ (std::string, fill_) | |
+ (double, fill_opacity_) | |
+ (std::string, halo_fill_) | |
+ (double, stroke_opacity_) | |
+ (double, halo_radius_) | |
+ (std::string, transform_) | |
+ ) | |
+ | |
+/*! | |
+ * mapnik::svg::text_output_attributes is adapted as a fusion sequence | |
+ * in order to be used directly by the text_output_attributes (below). | |
+ */ | |
+BOOST_FUSION_ADAPT_STRUCT( | |
+ mapnik::svg::text_output_attributes_fill, | |
+ (std::string, fontset_) | |
+ (double, text_size_) | |
+ (std::string, fill_) | |
+ (double, fill_opacity_) | |
+ (std::string, transform_) | |
+ ) | |
+ | |
+/*! | |
+ * mapnik::svg::text_output_attributes is adapted as a fusion sequence | |
+ * in order to be used directly by the text_output_attributes (below). | |
+ */ | |
+BOOST_FUSION_ADAPT_STRUCT( | |
+ mapnik::svg::text_output_attributes_stroke, | |
+ (std::string, fontset_) | |
+ (double, text_size_) | |
+ (std::string, halo_fill_) | |
+ (double, stroke_opacity_) | |
+ (double, halo_radius_) | |
+ (std::string, transform_) | |
+ ) | |
+ | |
namespace mapnik { namespace svg { | |
using namespace boost::spirit; | |
@@ -177,12 +223,77 @@ struct svg_root_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg: | |
<< lit(" height=") << confix('"', '"')[int_ << lit("px")] | |
<< " version=" << confix('"', '"')[double_] | |
<< " xmlns=" << confix('"', '"')[kstring] | |
- << lit(" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\""); | |
+ << lit(" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"") | |
+ << lit(" xmlns:xlink=\"http://www.w3.org/1999/xlink\""); | |
} | |
karma::rule<OutputIterator, mapnik::svg::root_output_attributes()> svg_root_attributes; | |
}; | |
-} | |
-} | |
+ | |
+template <typename OutputIterator> | |
+struct svg_text_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg::text_output_attributes()> | |
+{ | |
+ explicit svg_text_attributes_grammar() | |
+ : svg_text_attributes_grammar::base_type(svg_text_attributes) | |
+ { | |
+ karma::lit_type lit; | |
+ karma::string_type kstring; | |
+ karma::double_type double_; | |
+ repository::confix_type confix; | |
+ | |
+ svg_text_attributes = | |
+ lit(" font-family=") << confix('"', '"')[kstring] | |
+ << lit(" font-size=") << confix('"', '"')[double_ << lit("px")] | |
+ << lit(" fill=") << confix('"', '"')[kstring] << lit(" fill-opacity=") << confix('"', '"')[double_] | |
+ << lit(" style=\"") << lit("stroke: ") << kstring << lit("; stroke-opacity: ") << double_ << "; stroke-width: " << double_ << lit("\"") | |
+ << lit(" text-transform=") << confix('"', '"')[kstring]; | |
+ } | |
+ | |
+ karma::rule<OutputIterator, mapnik::svg::text_output_attributes()> svg_text_attributes; | |
+}; | |
+ | |
+template <typename OutputIterator> | |
+struct svg_text_fill_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg::text_output_attributes_fill()> | |
+{ | |
+ explicit svg_text_fill_attributes_grammar() | |
+ : svg_text_fill_attributes_grammar::base_type(svg_text_attributes_fill) | |
+ { | |
+ karma::lit_type lit; | |
+ karma::string_type kstring; | |
+ karma::double_type double_; | |
+ repository::confix_type confix; | |
+ | |
+ svg_text_attributes_fill = | |
+ lit(" font-family=") << confix('"', '"')[kstring] | |
+ << lit(" font-size=") << confix('"', '"')[double_ << lit("px")] | |
+ << lit(" fill=") << confix('"', '"')[kstring] << lit(" fill-opacity=") << confix('"', '"')[double_] | |
+ << lit(" text-transform=") << confix('"', '"')[kstring]; | |
+ } | |
+ | |
+ karma::rule<OutputIterator, mapnik::svg::text_output_attributes_fill()> svg_text_attributes_fill; | |
+}; | |
+ | |
+template <typename OutputIterator> | |
+struct svg_text_stroke_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg::text_output_attributes_stroke()> | |
+{ | |
+ explicit svg_text_stroke_attributes_grammar() | |
+ : svg_text_stroke_attributes_grammar::base_type(svg_text_attributes_stroke) | |
+ { | |
+ karma::lit_type lit; | |
+ karma::string_type kstring; | |
+ karma::double_type double_; | |
+ repository::confix_type confix; | |
+ | |
+ svg_text_attributes_stroke = | |
+ lit(" font-family=") << confix('"', '"')[kstring] | |
+ << lit(" font-size=") << confix('"', '"')[double_ << lit("px")] | |
+ << lit(" fill=\"none\"") | |
+ << lit(" style=\"") << lit("stroke: ") << kstring << lit("; stroke-opacity: ") << double_ << "; stroke-width: " << double_ << lit("\"") | |
+ << lit(" text-transform=") << confix('"', '"')[kstring]; | |
+ } | |
+ | |
+ karma::rule<OutputIterator, mapnik::svg::text_output_attributes_stroke()> svg_text_attributes_stroke; | |
+}; | |
+ }} | |
#endif // SVG_OUTPUT_GRAMMARS_HPP | |
diff --git a/include/mapnik/text/glyph_info.hpp b/include/mapnik/text/glyph_info.hpp | |
index a387045..644c6b3 100644 | |
--- a/include/mapnik/text/glyph_info.hpp | |
+++ b/include/mapnik/text/glyph_info.hpp | |
@@ -23,6 +23,7 @@ | |
#define MAPNIK_GLYPH_INFO_HPP | |
//mapnik | |
+#include <mapnik/value.hpp> | |
#include <mapnik/text/char_properties_ptr.hpp> | |
#include <mapnik/pixel_position.hpp> | |
@@ -47,7 +48,8 @@ struct glyph_info | |
ymax(0.0), | |
line_height(0.0), | |
offset(), | |
- format() {} | |
+ format(), | |
+ orig(0) {} | |
glyph_index_t glyph_index; | |
face_ptr face; | |
// Position in the string of all characters i.e. before itemizing | |
@@ -61,6 +63,7 @@ struct glyph_info | |
pixel_position offset; | |
char_properties_ptr format; | |
double height() const { return ymax-ymin; } | |
+ std::shared_ptr<value_unicode_string> orig; | |
}; | |
} //ns mapnik | |
diff --git a/include/mapnik/text/harfbuzz_shaper.hpp b/include/mapnik/text/harfbuzz_shaper.hpp | |
index 2b0c5f9..bd6275d 100644 | |
--- a/include/mapnik/text/harfbuzz_shaper.hpp | |
+++ b/include/mapnik/text/harfbuzz_shaper.hpp | |
@@ -97,6 +97,8 @@ static void shape_text(text_line & line, | |
continue; | |
} | |
+ std::shared_ptr<value_unicode_string> curr_item(new value_unicode_string()); | |
+ text.extract(text_item.start, text_item.end - text_item.start, *curr_item.get()); | |
for (unsigned i=0; i<num_glyphs; ++i) | |
{ | |
glyph_info tmp; | |
@@ -109,6 +111,7 @@ static void shape_text(text_line & line, | |
tmp.width = positions[i].x_advance >> 6; | |
tmp.offset.set(positions[i].x_offset / 64.0, positions[i].y_offset / 64.0); | |
width_map[glyphs[i].cluster] += tmp.width; | |
+ tmp.orig = curr_item; | |
line.add_glyph(tmp, scale_factor); | |
} | |
line.update_max_char_height(face->get_char_height()); | |
diff --git a/include/mapnik/text/icu_shaper.hpp b/include/mapnik/text/icu_shaper.hpp | |
index db5246a..35641a5 100644 | |
--- a/include/mapnik/text/icu_shaper.hpp | |
+++ b/include/mapnik/text/icu_shaper.hpp | |
@@ -90,6 +90,8 @@ static void shape_text(text_line & line, | |
{ | |
U_NAMESPACE_QUALIFIER StringCharacterIterator iter(shaped); | |
unsigned i = 0; | |
+ std::shared_ptr<value_unicode_string> curr_item(new value_unicode_string()); | |
+ text.extract(text_item.start, text_item.end - text_item.start, *curr_item.get()); | |
for (iter.setToStart(); iter.hasNext();) | |
{ | |
UChar ch = iter.nextPostInc(); | |
@@ -104,6 +106,7 @@ static void shape_text(text_line & line, | |
} | |
tmp.face = face; | |
tmp.format = text_item.format; | |
+ tmp.orig = curr_item; | |
face->glyph_dimensions(tmp); | |
width_map[i] += tmp.width; | |
line.add_glyph(tmp, scale_factor); | |
diff --git a/include/mapnik/value_types.hpp b/include/mapnik/value_types.hpp | |
index 6807906..c78e46f 100644 | |
--- a/include/mapnik/value_types.hpp | |
+++ b/include/mapnik/value_types.hpp | |
@@ -23,6 +23,10 @@ | |
#ifndef MAPNIK_VALUE_TYPES_HPP | |
#define MAPNIK_VALUE_TYPES_HPP | |
+#ifndef BOOST_SPIRIT_UNICODE | |
+#define BOOST_SPIRIT_UNICODE | |
+#endif | |
+ | |
// icu | |
#include <unicode/unistr.h> // for UnicodeString | |
diff --git a/src/color.cpp b/src/color.cpp | |
index 1b8a87d..d833dba 100644 | |
--- a/src/color.cpp | |
+++ b/src/color.cpp | |
@@ -91,6 +91,26 @@ std::string color::to_hex_string() const | |
return str; | |
} | |
+std::string color::to_hex_string_no_alpha() const | |
+{ | |
+ namespace karma = boost::spirit::karma; | |
+ boost::spirit::karma::_1_type _1; | |
+ boost::spirit::karma::hex_type hex; | |
+ boost::spirit::karma::eps_type eps; | |
+ boost::spirit::karma::right_align_type right_align; | |
+ std::string str; | |
+ std::back_insert_iterator<std::string> sink(str); | |
+ karma::generate(sink, | |
+ // begin grammar | |
+ '#' | |
+ << right_align(2,'0')[hex[_1 = red()]] | |
+ << right_align(2,'0')[hex[_1 = green()]] | |
+ << right_align(2,'0')[hex[_1 = blue()]] | |
+ // end grammar | |
+ ); | |
+ return str; | |
+} | |
+ | |
void color::premultiply() | |
{ | |
agg::rgba8 pre_c = agg::rgba8(red_,green_,blue_,alpha_); | |
diff --git a/src/svg/output/process_text_symbolizer.cpp b/src/svg/output/process_text_symbolizer.cpp | |
index b21f24d..e2cc70f 100644 | |
--- a/src/svg/output/process_text_symbolizer.cpp | |
+++ b/src/svg/output/process_text_symbolizer.cpp | |
@@ -24,15 +24,130 @@ | |
// mapnik | |
#include <mapnik/svg/output/svg_renderer.hpp> | |
+#include <mapnik/text/symbolizer_helpers.hpp> | |
namespace mapnik | |
{ | |
+// extends a curve at both endpoints such that the resulting curve | |
+// is smooth at the endpoints and hopefully matches the profile of the curve | |
+// in the background. this needs to be done because the path outputted | |
+// by the shapers does not always fit the text when rendered not by mapnik | |
+void extend_curve(int num_pts, std::deque<double> &x, std::deque<double> &y) { | |
+ if(x.size() > 1 && y.size() > 1) { | |
+ double dx1 = x[0]-x[1], dy1 = y[0]-y[1]; | |
+ for(int i = 0; i < num_pts; i++) { | |
+ x.push_front(x[0]+dx1*(i+1)); | |
+ y.push_front(y[0]+dy1*(i+1)); | |
+ } | |
+ | |
+ int len = x.size(); | |
+ double dx2 = x[len-1]-x[len-2], dy2 = y[len-1]-y[len-2]; | |
+ for(int i = 0; i < num_pts; i++) { | |
+ x.push_back(x[len-1]+dx2*(i+1)); | |
+ y.push_back(y[len-1]+dy2*(i+1)); | |
+ } | |
+ } | |
+} | |
+ | |
template <typename T> | |
void svg_renderer<T>::process(text_symbolizer const& sym, | |
mapnik::feature_impl & feature, | |
proj_transform const& prj_trans) | |
{ | |
- // nothing yet. | |
+ typedef coord_transform<CoordTransform, geometry_type> path_type; | |
+ | |
+ double inf = std::numeric_limits<double>::max(); | |
+ box2d<double> clip_box(-inf, -inf, inf, inf); | |
+ | |
+ // find positions for all the glyphs | |
+ text_symbolizer_helper helper( | |
+ sym, feature, prj_trans, | |
+ common_.width_, common_.height_, | |
+ common_.scale_factor_, | |
+ common_.t_, common_.font_manager_, *common_.detector_, | |
+ clip_box); | |
+ | |
+ // leave the path attributes empty | |
+ svg::path_output_attributes line_attr; | |
+ | |
+ // halo effect is emulated by having 2 copies of the | |
+ // text. one with fill only, one with stroke only | |
+ // it can be done with filters but there are libraries | |
+ // that don't support filter (especially in android) | |
+ svg::text_output_attributes_fill text_attr; | |
+ text_attr.set_text_ratio(sym.get_text_ratio()); | |
+ text_attr.set_face_name(sym.get_face_name()); | |
+ if(sym.get_fontset()) | |
+ text_attr.set_fontset(sym.get_fontset()->get_name()); | |
+ text_attr.set_text_size(get<double>(sym, keys::text_size, feature)); | |
+ text_attr.set_fill(get<mapnik::color>(sym, keys::fill, feature)); | |
+ text_attr.set_char_spacing(sym.get_character_spacing()); | |
+ text_attr.set_text_transform(sym.get_text_transform()); | |
+ | |
+ // the halo duplicate of the text | |
+ svg::text_output_attributes_stroke halo_attr; | |
+ halo_attr.set_text_ratio(sym.get_text_ratio()); | |
+ halo_attr.set_face_name(sym.get_face_name()); | |
+ if(sym.get_fontset()) { | |
+ halo_attr.set_fontset(sym.get_fontset()->get_name()); | |
+ } | |
+ halo_attr.set_text_size(sym.get_text_size()); | |
+ halo_attr.set_halo_fill(sym.get_halo_fill()); | |
+ // default stroke width in svg is 1.0 | |
+ halo_attr.set_halo_radius(1.0+sym.get_halo_radius()); | |
+ halo_attr.set_char_spacing(sym.get_character_spacing()); | |
+ halo_attr.set_text_transform(sym.get_text_transform()); | |
+ | |
+ // extract glyph positions | |
+ placements_list const& placements = helper.get(); | |
+ for (glyph_positions_ptr glyphs : placements) | |
+ { | |
+ // reconstruct geometry for text placing | |
+ std::deque<double> x,y; | |
+ value_unicode_string prev = ""; | |
+ if(glyphs->begin() != glyphs->end()) | |
+ prev = *(glyphs->begin()->glyph->orig.get()); | |
+ pixel_position base = glyphs->get_base_point(); base.y = height_-base.y; | |
+ for(auto it = glyphs->begin(); it != glyphs->end(); ++it) | |
+ { | |
+ value_unicode_string curr = *(it->glyph->orig.get()); | |
+ if(curr != prev) { | |
+ // create geometry from the accumulated positions | |
+ extend_curve(1, x, y); | |
+ geometry_type geom(geometry_type::LineString); | |
+ for(int i = 0; i < x.size(); i++) { | |
+ if(i == 0) | |
+ geom.move_to(x[i], y[i]); | |
+ else | |
+ geom.line_to(x[i], y[i]); | |
+ } | |
+ | |
+ generator_.generate_text_on_path(prev, text_attr, halo_attr, geom, line_attr); | |
+ prev = curr; | |
+ | |
+ x.clear(); y.clear(); | |
+ } | |
+ | |
+ // determine position of character in the string | |
+ pixel_position pos = it->pos+it->glyph->offset.rotate(it->rot)+base; | |
+ // translate to svg coordinate space | |
+ x.push_back(pos.x); | |
+ y.push_back(height_-pos.y); | |
+ } | |
+ | |
+ // create text on geometry specified by the glyph positions | |
+ if(x.size() > 0) { | |
+ extend_curve(1, x, y); | |
+ geometry_type geom(geometry_type::LineString); | |
+ for(int i = 0; i < x.size(); i++) { | |
+ if(i == 0) | |
+ geom.move_to(x[i], y[i]); | |
+ else | |
+ geom.line_to(x[i], y[i]); | |
+ } | |
+ generator_.generate_text_on_path(prev, text_attr, halo_attr, geom, line_attr); | |
+ } | |
+ } | |
} | |
template void svg_renderer<std::ostream_iterator<char> >::process(text_symbolizer const& sym, | |
diff --git a/src/svg/output/svg_output_attributes.cpp b/src/svg/output/svg_output_attributes.cpp | |
index 972fbb7..d61eaec 100644 | |
--- a/src/svg/output/svg_output_attributes.cpp | |
+++ b/src/svg/output/svg_output_attributes.cpp | |
@@ -289,7 +289,129 @@ namespace mapnik { namespace svg { | |
svg_version_ = SVG_VERSION; | |
svg_namespace_url_ = SVG_NAMESPACE_URL; | |
} | |
- }} | |
-#endif | |
+ // | |
+ // text_output_attributes | |
+ // | |
+ | |
+ void text_output_attributes::set_text_ratio(const double ratio) { | |
+ text_ratio_ = ratio; | |
+ } | |
+ | |
+ void text_output_attributes::set_face_name(const std::string &name) { | |
+ face_name_ = name; | |
+ } | |
+ | |
+ void text_output_attributes::set_fontset(const std::string &name) { | |
+ fontset_ = name; | |
+ } | |
+ | |
+ void text_output_attributes::set_text_size(const double size) { | |
+ text_size_ = size; | |
+ } | |
+ | |
+ void text_output_attributes::set_char_spacing(const double &space) { | |
+ char_spacing_ = space; | |
+ } | |
+ | |
+ void text_output_attributes::set_text_transform(const text_transform_e &trans) { | |
+ switch(trans) { | |
+ case text_transform::NONE: | |
+ case text_transform::UPPERCASE: | |
+ case text_transform::LOWERCASE: | |
+ case text_transform::CAPITALIZE: | |
+ case text_transform::text_transform_MAX: | |
+ default: | |
+ break; | |
+ } | |
+ } | |
+ | |
+ double text_output_attributes::text_ratio() const { | |
+ return text_ratio_; | |
+ } | |
+ | |
+ std::string text_output_attributes::face_name() const { | |
+ return face_name_; | |
+ } | |
+ | |
+ std::string text_output_attributes::fontset() const { | |
+ return fontset_; | |
+ } | |
+ | |
+ double text_output_attributes::text_size() const { | |
+ return text_size_; | |
+ } | |
+ | |
+ double text_output_attributes::char_spacing() const { | |
+ return char_spacing_; | |
+ } | |
+ | |
+ std::string text_output_attributes::transform() const { | |
+ return transform_; | |
+ } | |
+ | |
+ void text_output_attributes::reset() { | |
+ text_ratio_ = 0; | |
+ text_size_ = 10; | |
+ char_spacing_ = 0; | |
+ transform_ = "none"; | |
+ } | |
+ | |
+ // | |
+ // text_output_attributes_fill | |
+ // | |
+ | |
+ void text_output_attributes_fill::set_fill(const color &fill) { | |
+ fill_ = fill.to_hex_string_no_alpha(); | |
+ fill_opacity_ = fill.alpha()/(double)(0xff); | |
+ } | |
+ | |
+ std::string text_output_attributes_fill::fill() const { | |
+ return fill_; | |
+ } | |
+ | |
+ double text_output_attributes_fill::fill_opacity() const { | |
+ return fill_opacity_; | |
+ } | |
+ | |
+ void text_output_attributes_fill::reset() { | |
+ static_cast<text_output_attributes*>(this)->reset(); | |
+ fill_ = "#000000"; | |
+ fill_opacity_ = 1.0; | |
+ } | |
+ | |
+ // | |
+ // text_output_attributes_stroke | |
+ // | |
+ | |
+ void text_output_attributes_stroke::set_halo_fill(const color &fill) { | |
+ halo_fill_ = fill.to_hex_string_no_alpha(); | |
+ stroke_opacity_ = fill.alpha()/(double)(0xff); | |
+ } | |
+ | |
+ void text_output_attributes_stroke::set_halo_radius(const double &radius) { | |
+ halo_radius_ = radius; | |
+ } | |
+ | |
+ std::string text_output_attributes_stroke::halo_fill() const { | |
+ return halo_fill_; | |
+ } | |
+ | |
+ double text_output_attributes_stroke::stroke_opacity() const { | |
+ return stroke_opacity_; | |
+ } | |
+ | |
+ double text_output_attributes_stroke::halo_radius() const { | |
+ return halo_radius_; | |
+ } | |
+ | |
+ void text_output_attributes_stroke::reset() { | |
+ static_cast<text_output_attributes*>(this)->reset(); | |
+ halo_fill_ = "#000000"; | |
+ stroke_opacity_ = 1.0; | |
+ halo_radius_ = 1.0; | |
+ } | |
+ | |
+ }} | |
+#endif // defined(SVG_RENDERER) | |
\ No newline at end of file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment