From 998bf593ef05b0afea5f6479c97dbd4ef6244f9b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Sat, 16 Jun 2012 23:54:14 -0400 Subject: [PATCH 01/11] svg parsing: support empty paths and avoid leaking file descriptors in the case of invalid paths - closes #1256 --- src/svg_parser.cpp | 55 +++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/svg_parser.cpp b/src/svg_parser.cpp index 0f4412e25..22a2ed766 100644 --- a/src/svg_parser.cpp +++ b/src/svg_parser.cpp @@ -139,10 +139,17 @@ void svg_parser::parse(std::string const& filename) if (reader != 0) { int ret = xmlTextReaderRead(reader); - while (ret == 1) + try { + while (ret == 1) + { + process_node(reader); + ret = xmlTextReaderRead(reader); + } + } + catch (std::exception const& ex) { - process_node(reader); - ret = xmlTextReaderRead(reader); + xmlFreeTextReader(reader); + throw; } xmlFreeTextReader(reader); if (ret != 0) @@ -428,26 +435,34 @@ void svg_parser::parse_path(xmlTextReaderPtr reader) value = xmlTextReaderGetAttribute(reader, BAD_CAST "d"); if (value) { - path_.begin_path(); - - if (!mapnik::svg::parse_path((const char*) value, path_)) + // d="" (empty paths) are valid + if (strlen((const char*)value) < 1) { xmlFree(value); - xmlChar *id_value; - id_value = xmlTextReaderGetAttribute(reader, BAD_CAST "id"); - if (id_value) - { - std::string id_string((const char *) id_value); - xmlFree(id_value); - throw std::runtime_error(std::string("unable to parse invalid svg with id '") + id_string + "'"); - } - else - { - throw std::runtime_error("unable to parse invalid svg "); - } } - path_.end_path(); - xmlFree(value); + else + { + path_.begin_path(); + + if (!mapnik::svg::parse_path((const char*) value, path_)) + { + xmlFree(value); + xmlChar *id_value; + id_value = xmlTextReaderGetAttribute(reader, BAD_CAST "id"); + if (id_value) + { + std::string id_string((const char *) id_value); + xmlFree(id_value); + throw std::runtime_error(std::string("unable to parse invalid svg with id '") + id_string + "'"); + } + else + { + throw std::runtime_error("unable to parse invalid svg "); + } + } + path_.end_path(); + xmlFree(value); + } } } From 6281dec04bf2756802623104eea871e39c4b69ab Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Sun, 17 Jun 2012 15:16:13 -0400 Subject: [PATCH 02/11] + add missing headers --- src/parse_transform.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/parse_transform.cpp b/src/parse_transform.cpp index 325d440c6..6892c2cb9 100644 --- a/src/parse_transform.cpp +++ b/src/parse_transform.cpp @@ -22,6 +22,8 @@ #include #include +#include +#include #include From b9765ec1db829639d29174b7d69f0bda87ab1dd1 Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Sun, 17 Jun 2012 15:16:48 -0400 Subject: [PATCH 03/11] + hsl and hsv colour spaces (boost/gil/extensions) --- boost/gil/extension/toolbox/hsl.hpp | 263 ++++++++++++++++++++++++++++ boost/gil/extension/toolbox/hsv.hpp | 231 ++++++++++++++++++++++++ 2 files changed, 494 insertions(+) create mode 100644 boost/gil/extension/toolbox/hsl.hpp create mode 100644 boost/gil/extension/toolbox/hsv.hpp diff --git a/boost/gil/extension/toolbox/hsl.hpp b/boost/gil/extension/toolbox/hsl.hpp new file mode 100644 index 000000000..d22afef19 --- /dev/null +++ b/boost/gil/extension/toolbox/hsl.hpp @@ -0,0 +1,263 @@ +// Copyright 2007 Christian Henning. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/*************************************************************************************************/ + +#ifndef GIL_HSL_H +#define GIL_HSL_H + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief Support for HSL color space +/// \author Christian Henning \n +//////////////////////////////////////////////////////////////////////////////////////// + +#include + +namespace boost { namespace gil { + +/// \addtogroup ColorNameModel +/// \{ +namespace hsl_color_space +{ +/// \brief Hue +struct hue_t {}; +/// \brief Saturation +struct saturation_t {}; +/// \brief Lightness +struct lightness_t {}; +} +/// \} + +/// \ingroup ColorSpaceModel +typedef mpl::vector3< hsl_color_space::hue_t + , hsl_color_space::saturation_t + , hsl_color_space::lightness_t + > hsl_t; + +/// \ingroup LayoutModel +typedef layout hsl_layout_t; + + +GIL_DEFINE_ALL_TYPEDEFS( 32f, hsl ); + +/// \ingroup ColorConvert +/// \brief RGB to HSL +template <> +struct default_color_converter_impl< rgb_t, hsl_t > +{ + template + void operator()( const P1& src, P2& dst ) const + { + using namespace hsl_color_space; + + // only bits32f for hsl is supported + bits32f temp_red = channel_convert( get_color( src, red_t() )); + bits32f temp_green = channel_convert( get_color( src, green_t() )); + bits32f temp_blue = channel_convert( get_color( src, blue_t() )); + + bits32f hue, saturation, lightness; + + 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 ( max_color - min_color < 0.001 ) + { + // rgb color is gray + + hue = 0.f; + saturation = 0.f; + + // doesn't matter which rgb channel we use. + lightness = temp_red; + } + else + { + + bits32f diff = max_color - min_color; + + // lightness calculation + + lightness = ( min_color + max_color ) / 2.f; + + // saturation calculation + + if( lightness < 0.5f ) + { + saturation = diff + / ( min_color + max_color ); + } + else + { + saturation = ( max_color - min_color ) + / ( 2.f - diff ); + + } + + // hue calculation + if( std::abs( max_color - temp_red ) < 0.0001f ) + { + // max_color is red + hue = ( temp_green - temp_blue ) + / diff; + + } + else if( std::abs( max_color - temp_green) < 0.0001f ) + { + // max_color is green + // 2.0 + (b - r) / (maxColor - minColor) + hue = 2.f + + ( temp_blue - temp_red ) + / diff; + + } + else + { + // max_color is blue + // 4.0 + (r - g) / (maxColor - minColor) + hue = 4.f + + ( temp_red - temp_green ) + / diff; + } + + hue /= 6.f; + + if( hue < 0.f ) + { + hue += 1.f; + } + } + + get_color( dst,hue_t() ) = hue; + get_color( dst,saturation_t() ) = saturation; + get_color( dst,lightness_t() ) = lightness; + } +}; + +/// \ingroup ColorConvert +/// \brief HSL to RGB +template <> +struct default_color_converter_impl +{ + template + void operator()( const P1& src, P2& dst) const + { + using namespace hsl_color_space; + + bits32f red, green, blue; + + if( std::abs( get_color( src, saturation_t() )) < 0.0001 ) + { + // If saturation is 0, the color is a shade of gray + red = get_color( src, lightness_t() ); + green = get_color( src, lightness_t() ); + blue = get_color( src, lightness_t() ); + } + else + { + float temp1, temp2; + float tempr, tempg, tempb; + + //Set the temporary values + if( get_color( src, lightness_t() ) < 0.5 ) + { + temp2 = get_color( src, lightness_t() ) + * ( 1.f + get_color( src, saturation_t() ) ); + } + else + { + temp2 = ( get_color( src, lightness_t() ) + get_color( src, saturation_t() )) + - ( get_color( src, lightness_t() ) * get_color( src, saturation_t() )); + } + + temp1 = 2.f + * get_color( src, lightness_t() ) + - temp2; + + tempr = get_color( src, hue_t() ) + 1.f / 3.f; + + if( tempr > 1.f ) + { + tempr--; + } + + tempg = get_color( src, hue_t() ); + tempb = get_color( src, hue_t() ) - 1.f / 3.f; + + if( tempb < 0.f ) + { + tempb++; + } + + //Red + if( tempr < 1.f / 6.f ) + { + red = temp1 + ( temp2 - temp1 ) * 6.f * tempr; + } + else if( tempr < 0.5f ) + { + red = temp2; + } + else if( tempr < 2.f / 3.f ) + { + red = temp1 + (temp2 - temp1) + * (( 2.f / 3.f ) - tempr) * 6.f; + } + else + { + red = temp1; + } + + //Green + if( tempg < 1.f / 6.f ) + { + green = temp1 + ( temp2 - temp1 ) * 6.f * tempg; + } + else if( tempg < 0.5f ) + { + green = temp2; + } + else if( tempg < 2.f / 3.f ) + { + green = temp1 + ( temp2 - temp1 ) + * (( 2.f / 3.f ) - tempg) * 6.f; + } + else + { + green = temp1; + } + + //Blue + if( tempb < 1.f / 6.f ) + { + blue = temp1 + (temp2 - temp1) * 6.f * tempb; + } + else if( tempb < 0.5f ) + { + blue = temp2; + } + else if( tempb < 2.f / 3.f ) + { + blue = temp1 + (temp2 - temp1) + * (( 2.f / 3.f ) - tempb) * 6.f; + } + else + { + blue = temp1; + } + } + + get_color(dst,red_t()) = + channel_convert::type>( red ); + get_color(dst,green_t())= + channel_convert::type>( green ); + get_color(dst,blue_t()) = + channel_convert::type>( blue ); + } +}; + +} } // namespace boost::gil + +#endif // GIL_HSL_H diff --git a/boost/gil/extension/toolbox/hsv.hpp b/boost/gil/extension/toolbox/hsv.hpp new file mode 100644 index 000000000..dc992feb0 --- /dev/null +++ b/boost/gil/extension/toolbox/hsv.hpp @@ -0,0 +1,231 @@ +// Copyright 2004 Christian Henning. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +/*************************************************************************************************/ + +#ifndef GIL_HSV_H +#define GIL_HSV_H + +//////////////////////////////////////////////////////////////////////////////////////// +/// \file +/// \brief Support for HSV color space +/// \author Christian Henning \n +//////////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +namespace boost { namespace gil { + +/// \addtogroup ColorNameModel +/// \{ +namespace hsv_color_space +{ +/// \brief Hue +struct hue_t {}; +/// \brief Saturation +struct saturation_t{}; +/// \brief Value +struct value_t {}; +} +/// \} + +/// \ingroup ColorSpaceModel +typedef mpl::vector3< hsv_color_space::hue_t + , hsv_color_space::saturation_t + , hsv_color_space::value_t + > hsv_t; + +/// \ingroup LayoutModel +typedef layout hsv_layout_t; + + +GIL_DEFINE_ALL_TYPEDEFS( 32f, hsv ) + +/// \ingroup ColorConvert +/// \brief RGB to HSV +template <> +struct default_color_converter_impl< rgb_t, hsv_t > +{ + template + void operator()( const P1& src, P2& dst ) const + { + using namespace hsv_color_space; + + // only bits32f for hsv is supported + bits32f temp_red = channel_convert( get_color( src, red_t() )); + bits32f temp_green = channel_convert( get_color( src, green_t() )); + bits32f temp_blue = channel_convert( get_color( src, blue_t() )); + + bits32f hue, saturation, value; + + 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 )); + + value = max_color; + + bits32f diff = max_color - min_color; + + if( max_color < 0.0001f ) + { + saturation = 0.f; + } + else + { + saturation = diff / max_color; + } + + + if( saturation < 0.0001f ) + { + //it doesn't matter what value it has + hue = 0.f; + } + else + { + if( (std::abs)( boost::numeric_cast(temp_red - max_color) ) < 0.0001f ) + { + hue = ( temp_green - temp_blue ) + / diff; + } + else if( temp_green == max_color ) + { + hue = 2.f + ( temp_blue - temp_red ) + / diff; + } + else + { + hue = 4.f + ( temp_red - temp_green ) + / diff; + } + + //to bring it to a number between 0 and 1 + hue /= 6.f; + + if( hue < 0.f ) + { + hue++; + } + } + + get_color( dst, hue_t() ) = hue; + get_color( dst, saturation_t() ) = saturation; + get_color( dst, value_t() ) = value; + } +}; + +/// \ingroup ColorConvert +/// \brief HSV to RGB +template <> +struct default_color_converter_impl +{ + template + void operator()( const P1& src, P2& dst) const + { + using namespace hsv_color_space; + + bits32f red, green, blue; + + //If saturation is 0, the color is a shade of gray + if( abs( get_color( src, saturation_t() )) < 0.0001f ) + { + // If saturation is 0, the color is a shade of gray + red = get_color( src, value_t() ); + green = get_color( src, value_t() ); + blue = get_color( src, value_t() ); + } + else + { + bits32f frac, p, q, t, h; + bits32 i; + + //to bring hue to a number between 0 and 6, better for the calculations + h = get_color( src, hue_t() ); + h *= 6.f; + + i = static_cast( floor( h )); + + frac = h - i; + + p = get_color( src, value_t() ) + * ( 1.f - get_color( src, saturation_t() )); + + q = get_color( src, value_t() ) + * ( 1.f - ( get_color( src, saturation_t() ) * frac )); + + t = get_color( src, value_t() ) + * ( 1.f - ( get_color( src, saturation_t() ) * ( 1.f - frac ))); + + switch( i ) + { + case 0: + { + red = get_color( src, value_t() ); + green = t; + blue = p; + + break; + } + + case 1: + { + red = q; + green = get_color( src, value_t() ); + blue = p; + + break; + } + + case 2: + { + red = p; + green = get_color( src, value_t() ); + blue = t; + + break; + } + + case 3: + { + red = p; + green = q; + blue = get_color( src, value_t() ); + + break; + } + + case 4: + { + red = t; + green = p; + blue = get_color( src, value_t() ); + + break; + } + + case 5: + { + red = get_color( src, value_t() ); + green = p; + blue = q; + + break; + } + + } + } + + get_color(dst,red_t()) = + channel_convert::type>( red ); + get_color(dst,green_t())= + channel_convert::type>( green ); + get_color(dst,blue_t()) = + channel_convert::type>( blue ); + } +}; + +} } // namespace boost::gil + +#endif // GIL_HSV_H From 14d365d5724c3726d5cc9dc0d9adcea187ed2614 Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Sun, 17 Jun 2012 15:19:29 -0400 Subject: [PATCH 04/11] + hue, saturation, color and luminosity blending modes (HSL based) (http://en.wikipedia.org/wiki/Blend_modes#Hue.2C_saturation_and_luminosity) --- deps/agg/include/agg_pixfmt_rgba.h | 215 ++++++++++++++++++++++++++- include/mapnik/image_compositing.hpp | 6 +- src/cairo_renderer.cpp | 6 +- src/image_compositing.cpp | 4 + 4 files changed, 222 insertions(+), 9 deletions(-) diff --git a/deps/agg/include/agg_pixfmt_rgba.h b/deps/agg/include/agg_pixfmt_rgba.h index 7d2ef4f0a..ac196b21f 100644 --- a/deps/agg/include/agg_pixfmt_rgba.h +++ b/deps/agg/include/agg_pixfmt_rgba.h @@ -31,6 +31,12 @@ #include "agg_color_rgba.h" #include "agg_rendering_buffer.h" +#include +#include +#include + +#include + namespace agg { @@ -1470,7 +1476,200 @@ namespace agg } } }; + + template + struct comp_op_rgba_hue + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if (cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + + if (sa > 0) + { + using namespace boost; + using namespace gil; + using namespace hsl_color_space; + + rgb8_pixel_t rgb_src(sr,sg,sb); + rgb8_pixel_t rgb_dst(p[Order::R],p[Order::G],p[Order::B]); + hsl32f_pixel_t hsl_src,hsl_dst; + color_convert(rgb_src, hsl_src); + color_convert(rgb_dst, hsl_dst); + get_color(hsl_dst,hue_t()) = get_color(hsl_src,hue_t()); + color_convert(hsl_dst, rgb_dst); + p[Order::R] = get_color(rgb_dst,red_t()); + p[Order::G] = get_color(rgb_dst,green_t()); + p[Order::B] = get_color(rgb_dst,blue_t()); + calc_type da = p[Order::A]; + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + template + struct comp_op_rgba_saturation + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if (cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + + if (sa > 0) + { + using namespace boost; + using namespace gil; + using namespace hsl_color_space; + + rgb8_pixel_t rgb_src(sr,sg,sb); + rgb8_pixel_t rgb_dst(p[Order::R],p[Order::G],p[Order::B]); + hsl32f_pixel_t hsl_src,hsl_dst; + color_convert( rgb_src, hsl_src); + color_convert( rgb_dst, hsl_dst); + get_color(hsl_dst,saturation_t()) = get_color(hsl_src,saturation_t()); + color_convert(hsl_dst, rgb_dst); + p[Order::R] = get_color(rgb_dst,red_t()); + p[Order::G] = get_color(rgb_dst,green_t()); + p[Order::B] = get_color(rgb_dst,blue_t()); + calc_type da = p[Order::A]; + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + template + struct comp_op_rgba_color + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if (cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + + if (sa > 0) + { + using namespace boost; + using namespace gil; + using namespace hsl_color_space; + + rgb8_pixel_t rgb_src(sr,sg,sb); + rgb8_pixel_t rgb_dst(p[Order::R],p[Order::G],p[Order::B]); + hsl32f_pixel_t hsl_src,hsl_dst; + color_convert( rgb_src, hsl_src); + color_convert( rgb_dst, hsl_dst); + get_color(hsl_dst,hue_t()) = get_color(hsl_src,hue_t()); + get_color(hsl_dst,saturation_t()) = get_color(hsl_src,saturation_t()); + color_convert(hsl_dst, rgb_dst); + p[Order::R] = get_color(rgb_dst,red_t()); + p[Order::G] = get_color(rgb_dst,green_t()); + p[Order::B] = get_color(rgb_dst,blue_t()); + calc_type da = p[Order::A]; + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + + template + struct comp_op_rgba_luminosity + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if (cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + + if (sa > 0) + { + using namespace boost; + using namespace gil; + using namespace hsl_color_space; + + rgb8_pixel_t rgb_src(sr,sg,sb); + rgb8_pixel_t rgb_dst(p[Order::R],p[Order::G],p[Order::B]); + hsl32f_pixel_t hsl_src,hsl_dst; + color_convert( rgb_src, hsl_src); + color_convert( rgb_dst, hsl_dst); + get_color(hsl_dst,lightness_t()) = get_color(hsl_src,lightness_t()); + color_convert(hsl_dst, rgb_dst); + p[Order::R] = get_color(rgb_dst,red_t()); + p[Order::G] = get_color(rgb_dst,green_t()); + p[Order::B] = get_color(rgb_dst,blue_t()); + calc_type da = p[Order::A]; + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; //======================================================comp_op_table_rgba template struct comp_op_table_rgba @@ -1520,6 +1719,10 @@ namespace agg comp_op_rgba_invert_rgb ::blend_pix, comp_op_rgba_grain_merge::blend_pix, comp_op_rgba_grain_extract::blend_pix, + comp_op_rgba_hue::blend_pix, + comp_op_rgba_saturation::blend_pix, + comp_op_rgba_color::blend_pix, + comp_op_rgba_luminosity::blend_pix, 0 }; @@ -1557,15 +1760,13 @@ namespace agg comp_op_invert_rgb, //----comp_op_invert_rgb comp_op_grain_merge, //----comp_op_grain_merge_rgb comp_op_grain_extract, //----comp_op_grain_extract_rgb + comp_op_hue, //----comp_op_hue + comp_op_saturation, //----comp_op_saturation + comp_op_color, //----comp_op_color + comp_op_luminosity, //----comp_op_luminosity end_of_comp_op_e }; - - - - - - - + //====================================================comp_op_adaptor_rgba template struct comp_op_adaptor_rgba { diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index 09c9e0db1..cf56d3ca8 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -70,7 +70,11 @@ enum composite_mode_e invert, invert_rgb, grain_merge, - grain_extract + grain_extract, + hue, + saturation, + _color, + luminosity }; MAPNIK_DECL boost::optional comp_op_from_string(std::string const& name); diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 958faa4ee..59a1983ed 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -385,10 +385,14 @@ public: case invert_rgb: case grain_merge: case grain_extract: + case hue: + case saturation: + case _color: + case luminosity: break; } } - + void set_line_join(line_join_e join) { if (join == MITER_JOIN) diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index fb2fc61f7..3ab87f2b2 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -70,6 +70,10 @@ static const comp_op_lookup_type comp_lookup = boost::assign::list_of comp_op_from_string(std::string const& name) From 465842e0e4289cb54ac10d7cbe50a63ed443212f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Sun, 17 Jun 2012 16:21:20 -0400 Subject: [PATCH 05/11] agg build: stop restricting CPPPATH so that boost can be reliably found, post b9765ec1db82 --- deps/agg/build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/agg/build.py b/deps/agg/build.py index 9e2db94a3..04c67735a 100644 --- a/deps/agg/build.py +++ b/deps/agg/build.py @@ -28,4 +28,4 @@ if env['SUNCC']: else: cxxflags = env['CUSTOM_CXXFLAGS'] + ' -O%s -fPIC -DNDEBUG' % env['OPTIMIZATION'] -agg_env.StaticLibrary('agg', glob.glob('./src/' + '*.cpp'), LIBS=[], CPPPATH='./include', CXXFLAGS=cxxflags, LINKFLAGS=env['CUSTOM_LDFLAGS']) \ No newline at end of file +agg_env.StaticLibrary('agg', glob.glob('./src/' + '*.cpp'), LIBS=[], CXXFLAGS=cxxflags, LINKFLAGS=env['CUSTOM_LDFLAGS']) \ No newline at end of file From f6c10bbb7e84a7be329efc9235609248c58acca9 Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Mon, 18 Jun 2012 11:10:04 -0400 Subject: [PATCH 06/11] Add color_spin composite operation. --- deps/agg/include/agg_pixfmt_rgba.h | 50 ++++++++++++++++++++++++++++ include/mapnik/image_compositing.hpp | 3 +- src/cairo_renderer.cpp | 1 + src/image_compositing.cpp | 1 + 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/deps/agg/include/agg_pixfmt_rgba.h b/deps/agg/include/agg_pixfmt_rgba.h index ac196b21f..705bf89e2 100644 --- a/deps/agg/include/agg_pixfmt_rgba.h +++ b/deps/agg/include/agg_pixfmt_rgba.h @@ -1434,6 +1434,54 @@ namespace agg } }; + // color spin + template + struct comp_op_rgba_color_spin + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(value_type* p, + // source rgb + unsigned sr, unsigned sg, unsigned sb, + // source alpha and opacity + unsigned sa, unsigned cover) { + if (cover < 255) { + sa = (sa * cover + 255) >> 8; + } + p[Order::R] = (value_type)(((0 + base_mask) >> base_shift)); + p[Order::G] = (value_type)(((0 + base_mask) >> base_shift)); + p[Order::B] = (value_type)(((0 + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); + + // http://en.wikipedia.org/wiki/File:HSV-RGB-comparison.svg + if (p[Order::A] < 64) { + p[Order::G] = ((p[Order::A] - 64) * 4); + p[Order::B] = 255; + } + if (p[Order::A] >= 64 && p[Order::A] < 128) { + p[Order::G] = 255; + p[Order::B] = 255 - ((p[Order::A] - 64) * 4); + } + if (p[Order::A] >= 128 && p[Order::A] < 192) { + p[Order::R] = ((p[Order::A] - 128) * 4); + p[Order::G] = 255; + } + if (p[Order::A] >= 192) { + p[Order::R] = 255; + p[Order::G] = 255 - ((p[Order::A] - 192) * 4); + } + } + }; + // grain extract (GIMP) // E = I - M + 128 @@ -1723,6 +1771,7 @@ namespace agg comp_op_rgba_saturation::blend_pix, comp_op_rgba_color::blend_pix, comp_op_rgba_luminosity::blend_pix, + comp_op_rgba_color_spin::blend_pix, 0 }; @@ -1764,6 +1813,7 @@ namespace agg comp_op_saturation, //----comp_op_saturation comp_op_color, //----comp_op_color comp_op_luminosity, //----comp_op_luminosity + comp_op_color_spin, //----comp_op_luminosity end_of_comp_op_e }; diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index cf56d3ca8..dcccbfca9 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -74,7 +74,8 @@ enum composite_mode_e hue, saturation, _color, - luminosity + luminosity, + color_spin }; MAPNIK_DECL boost::optional comp_op_from_string(std::string const& name); diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 175f983d2..459379289 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -389,6 +389,7 @@ public: case saturation: case _color: case luminosity: + case color_spin: break; } } diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 3ab87f2b2..210478e3e 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -74,6 +74,7 @@ static const comp_op_lookup_type comp_lookup = boost::assign::list_of comp_op_from_string(std::string const& name) From 93d860aaa391940c802a983d362f0e38f2c00973 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 18 Jun 2012 11:57:42 -0400 Subject: [PATCH 07/11] CHANGELOG: Add release dates and git revisions --- CHANGELOG.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50e982d7e..33cdc7ada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ For a complete change history, see the SVN log. ## Mapnik 2.1.0 +Not yet released + - PostGIS: Added 'simplify_geometries' option - will trigger ST_Simplify on geometries before returning to Mapnik (#1179) - Improved error feedback for invalid values passed to map.query_point @@ -48,7 +50,9 @@ For a complete change history, see the SVN log. ## Mapnik 2.0.1 -(Packaged from 5cd3cb2efdaf7e9990a57e8e00b652a81aaa39ae) +Released April 10, 2012 + +(Packaged from 57347e9106) - Support for PostGIS 2.0 (#956,#1083) @@ -83,6 +87,10 @@ For a complete change history, see the SVN log. ## Mapnik 2.0.0 +Released September 26, 2012 + +(Packaged from 5b4c20eab3) + - Add minimum-path-length property to text_symbolizer to allow labels to be placed only on lines of a certain length (#865) - Add support for png quantization using fixed palettes (#843) @@ -170,7 +178,11 @@ For a complete change history, see the SVN log. - Implement MarkersSymbolizer in Cairo render and improve the markers placement finder. (#553) -# Mapnik 0.7.2 Release +# Mapnik 0.7.2 + +Released Oct 18, 2011 + +(Packaged from bc5cabeb6a) - Added forward compatibility for Mapnik 2.0 XML syntax (https://trac.mapnik.org/wiki/Mapnik2/Changes) @@ -212,10 +224,52 @@ For a complete change history, see the SVN log. - Fixed reading of label_position_tolerance on text_symbolizer and height for building_symbolizer +# Mapnik 0.7.1 -# Mapnik 0.7.0 Release +Released March 23, 2010 -(Packaged from r1574) +(Packaged from r1745/db89f1ca75) + +- Rasters: Various fixes and improvements to 8bit png output ([#522](https://github.com/mapnik/mapnik/issues/522),[#475](https://github.com/mapnik/mapnik/issues/475)) + +- XML: Save map buffer_size when serializing map. + +- SCons: Added new build options 'PRIORITIZE_LINKING' and 'LINK_PRIORITY'. The first is a boolean (default True) + of whether to use the new sorting implementation that gives explcit preference to custom or local paths + during compile and linking that will affect builds when duplicate libraries and include directories are on the + system. LINK_PRIORITY defaults to prioritizing internal sources of the mapnik source folder, then local/user + installed libraries over system libraries, but the option can be customized. Sorting not only ensures that + compiling and linking will more likely match the desired libraries but also gives more likelyhood to avoid + the scenario where libraries are linked that don't match the includes libmapnik compiled against. + +- XML: Fixed behavior of PolygonPatternSymbolizer and LinePatternSymbolizer whereby width, height, + and type of images is actually allowed to be optionally ommitted ([#508](https://github.com/mapnik/mapnik/issues/508)). This was added in r1543 but + only worked correctly for PointSymbolizer and ShieldSymbolizer. + +- Fixed reading of PostGIS data on Big Endian systems ([#515](https://github.com/mapnik/mapnik/issues/515)) + +- PostGIS: Added better support for alterative schemas ([#500](https://github.com/mapnik/mapnik/issues/500)) + +- AGG Renderer - Enforced default gamma function on all symbolizers to ensure proper antialiasing + even when gamma is modified on the PolygonSymbolizer. ([#512](https://github.com/mapnik/mapnik/issues/512)) + +- PNG: fixed png256 for large images and some improvements to reduce color corruptions ([#522](https://github.com/mapnik/mapnik/issues/522)) + +- PNG: Added new quantization method for indexed png format using hextree with full support for alpha + channel. Also new method has some optimizations for color gradients common when using elevation based + rasters. By default old method using octree is used. (r1680, r1683, [#477](https://github.com/mapnik/mapnik/issues/477)) + +- PNG: Added initial support for passing options to png writter like number of colors, transparency + support, quantization method and possibly other in future using type parameter. For example + "png8:c=128:t=1:m=h" limits palette to 128 colors, uses only binary transparency (0 - none, + 1 - binary, 2 - full), and new method of quantization using hextree (h - hextree, o - octree). + Existing type "png256" can be also written using "png8:c=256:m=o:t=2" (r1680, r1683, [#477](https://github.com/mapnik/mapnik/issues/477)) + +# Mapnik 0.7.0 + +Released January, 19 2010 + +(Packaged from r1574/a0da946be9) - Core: Fixed linking to external libagg (r1297,r1299) @@ -354,9 +408,9 @@ For a complete change history, see the SVN log. -# Mapnik 0.6.1 Release +# Mapnik 0.6.1 -(Packaged from r1247) +(Packaged from r1247/353ff576c7) - Plugins: expose list of registered plugins as a 'plugin_names()' method of DatasourceCache (r1180) @@ -438,9 +492,9 @@ For a complete change history, see the SVN log. -# Mapnik 0.6.0 Release +# Mapnik 0.6.0 -(Packaged from r1066) +(Packaged from r1066/c88e03436f) - Python: Added support for aspect_fix_mode (r1013) From 396de8d08dec4d1b155a7cc52e7790832307e9aa Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 18 Jun 2012 12:08:38 -0400 Subject: [PATCH 08/11] add 0.3.0->0.5.1 to the CHANGELOG, correct the the 2.0.0 release year --- CHANGELOG.md | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33cdc7ada..33a7f8803 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ A simple log of core changes affecting Mapnik usage. Developers: Please commit along with changes. -For a complete change history, see the SVN log. +For a complete change history, see the git log. ## Mapnik 2.1.0 @@ -87,7 +87,7 @@ Released April 10, 2012 ## Mapnik 2.0.0 -Released September 26, 2012 +Released September 26, 2011 (Packaged from 5b4c20eab3) @@ -224,6 +224,7 @@ Released Oct 18, 2011 - Fixed reading of label_position_tolerance on text_symbolizer and height for building_symbolizer + # Mapnik 0.7.1 Released March 23, 2010 @@ -265,6 +266,7 @@ Released March 23, 2010 1 - binary, 2 - full), and new method of quantization using hextree (h - hextree, o - octree). Existing type "png256" can be also written using "png8:c=256:m=o:t=2" (r1680, r1683, [#477](https://github.com/mapnik/mapnik/issues/477)) + # Mapnik 0.7.0 Released January, 19 2010 @@ -407,9 +409,10 @@ Released January, 19 2010 - Fonts: Added unifont to auto-installed fonts, which is used by the OSM styles as a fallback font (r1328) - # Mapnik 0.6.1 +Released July 14, 2009 + (Packaged from r1247/353ff576c7) - Plugins: expose list of registered plugins as a 'plugin_names()' method of DatasourceCache (r1180) @@ -491,9 +494,10 @@ Released January, 19 2010 - Plugins: Fixed segfault in OGR Plugin with empty geometries (r1074) (#292) - # Mapnik 0.6.0 +Released April 1, 2009 + (Packaged from r1066/c88e03436f) - Python: Added support for aspect_fix_mode (r1013) @@ -584,3 +588,27 @@ Released January, 19 2010 - Plugins: Use memory mapped files for reading shape file (r628) - Core: Use streams to write images (i/o refactor) (r628) (#15) + +# Mapnik 0.5.1 + +Released April 15, 2008 + +(Packaged from c29cb7386d) + +# Mapnik 0.5.0 + +Released April 15, 2008 + +(Packaged from 0464a3563c) + +# Mapnik 0.4.0 + +Released February 26, 2007 + +(Packaged from 8d73e3a8dc) + +# Mapnik 0.3.0 + +Released May 22, 2006 + +(Packaged from 3ae046ebe2) From 0668fe2958a2cbd5400b7f1b19f56157a56630e8 Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Mon, 18 Jun 2012 14:29:03 -0400 Subject: [PATCH 09/11] + use std::abs --- boost/gil/extension/toolbox/hsv.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/boost/gil/extension/toolbox/hsv.hpp b/boost/gil/extension/toolbox/hsv.hpp index dc992feb0..afaf1ff8a 100644 --- a/boost/gil/extension/toolbox/hsv.hpp +++ b/boost/gil/extension/toolbox/hsv.hpp @@ -61,8 +61,8 @@ struct default_color_converter_impl< rgb_t, hsv_t > bits32f hue, saturation, value; - 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 )); + 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)); value = max_color; @@ -85,7 +85,7 @@ struct default_color_converter_impl< rgb_t, hsv_t > } else { - if( (std::abs)( boost::numeric_cast(temp_red - max_color) ) < 0.0001f ) + if( std::abs( boost::numeric_cast(temp_red - max_color) ) < 0.0001f ) { hue = ( temp_green - temp_blue ) / diff; @@ -129,7 +129,7 @@ struct default_color_converter_impl bits32f red, green, blue; //If saturation is 0, the color is a shade of gray - if( abs( get_color( src, saturation_t() )) < 0.0001f ) + if( std::abs( get_color( src, saturation_t() )) < 0.0001f ) { // If saturation is 0, the color is a shade of gray red = get_color( src, value_t() ); From c71944bf324ff218f4d50be471dd111f1ea817c3 Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Mon, 18 Jun 2012 14:30:01 -0400 Subject: [PATCH 10/11] + use HSV color space (as in GIMP) + rename 'luminosity' to 'value' --- deps/agg/include/agg_pixfmt_rgba.h | 77 ++++++++++++---------------- include/mapnik/image_compositing.hpp | 2 +- src/cairo_renderer.cpp | 2 +- src/image_compositing.cpp | 2 +- 4 files changed, 37 insertions(+), 46 deletions(-) diff --git a/deps/agg/include/agg_pixfmt_rgba.h b/deps/agg/include/agg_pixfmt_rgba.h index ac196b21f..972184251 100644 --- a/deps/agg/include/agg_pixfmt_rgba.h +++ b/deps/agg/include/agg_pixfmt_rgba.h @@ -32,7 +32,6 @@ #include "agg_rendering_buffer.h" #include -#include #include #include @@ -1476,7 +1475,7 @@ namespace agg } } }; - + template struct comp_op_rgba_hue { @@ -1507,20 +1506,18 @@ namespace agg { using namespace boost; using namespace gil; - using namespace hsl_color_space; - + using namespace hsv_color_space; rgb8_pixel_t rgb_src(sr,sg,sb); rgb8_pixel_t rgb_dst(p[Order::R],p[Order::G],p[Order::B]); - hsl32f_pixel_t hsl_src,hsl_dst; - color_convert(rgb_src, hsl_src); - color_convert(rgb_dst, hsl_dst); - get_color(hsl_dst,hue_t()) = get_color(hsl_src,hue_t()); - color_convert(hsl_dst, rgb_dst); + hsv32f_pixel_t hsv_src,hsv_dst; + color_convert(rgb_src, hsv_src); + color_convert(rgb_dst, hsv_dst); + get_color(hsv_dst,hue_t()) = get_color(hsv_src,hue_t()); + color_convert(hsv_dst, rgb_dst); p[Order::R] = get_color(rgb_dst,red_t()); p[Order::G] = get_color(rgb_dst,green_t()); p[Order::B] = get_color(rgb_dst,blue_t()); - calc_type da = p[Order::A]; - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); } } }; @@ -1555,20 +1552,18 @@ namespace agg { using namespace boost; using namespace gil; - using namespace hsl_color_space; - + using namespace hsv_color_space; rgb8_pixel_t rgb_src(sr,sg,sb); rgb8_pixel_t rgb_dst(p[Order::R],p[Order::G],p[Order::B]); - hsl32f_pixel_t hsl_src,hsl_dst; - color_convert( rgb_src, hsl_src); - color_convert( rgb_dst, hsl_dst); - get_color(hsl_dst,saturation_t()) = get_color(hsl_src,saturation_t()); - color_convert(hsl_dst, rgb_dst); + hsv32f_pixel_t hsv_src,hsv_dst; + color_convert( rgb_src, hsv_src); + color_convert( rgb_dst, hsv_dst); + get_color(hsv_dst,saturation_t()) = get_color(hsv_src,saturation_t()); + color_convert(hsv_dst, rgb_dst); p[Order::R] = get_color(rgb_dst,red_t()); p[Order::G] = get_color(rgb_dst,green_t()); p[Order::B] = get_color(rgb_dst,blue_t()); - calc_type da = p[Order::A]; - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); } } }; @@ -1603,28 +1598,26 @@ namespace agg { using namespace boost; using namespace gil; - using namespace hsl_color_space; - + using namespace hsv_color_space; rgb8_pixel_t rgb_src(sr,sg,sb); rgb8_pixel_t rgb_dst(p[Order::R],p[Order::G],p[Order::B]); - hsl32f_pixel_t hsl_src,hsl_dst; - color_convert( rgb_src, hsl_src); - color_convert( rgb_dst, hsl_dst); - get_color(hsl_dst,hue_t()) = get_color(hsl_src,hue_t()); - get_color(hsl_dst,saturation_t()) = get_color(hsl_src,saturation_t()); - color_convert(hsl_dst, rgb_dst); + hsv32f_pixel_t hsv_src,hsv_dst; + color_convert( rgb_src, hsv_src); + color_convert( rgb_dst, hsv_dst); + get_color(hsv_dst,hue_t()) = get_color(hsv_src,hue_t()); + get_color(hsv_dst,saturation_t()) = get_color(hsv_src,saturation_t()); + color_convert(hsv_dst, rgb_dst); p[Order::R] = get_color(rgb_dst,red_t()); p[Order::G] = get_color(rgb_dst,green_t()); p[Order::B] = get_color(rgb_dst,blue_t()); - calc_type da = p[Order::A]; - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); } } }; template - struct comp_op_rgba_luminosity + struct comp_op_rgba_value { typedef ColorT color_type; typedef Order order_type; @@ -1653,20 +1646,18 @@ namespace agg { using namespace boost; using namespace gil; - using namespace hsl_color_space; - + using namespace hsv_color_space; rgb8_pixel_t rgb_src(sr,sg,sb); rgb8_pixel_t rgb_dst(p[Order::R],p[Order::G],p[Order::B]); - hsl32f_pixel_t hsl_src,hsl_dst; - color_convert( rgb_src, hsl_src); - color_convert( rgb_dst, hsl_dst); - get_color(hsl_dst,lightness_t()) = get_color(hsl_src,lightness_t()); - color_convert(hsl_dst, rgb_dst); + hsv32f_pixel_t hsv_src,hsv_dst; + color_convert( rgb_src, hsv_src); + color_convert( rgb_dst, hsv_dst); + get_color(hsv_dst,value_t()) = get_color(hsv_src,value_t()); + color_convert(hsv_dst, rgb_dst); p[Order::R] = get_color(rgb_dst,red_t()); p[Order::G] = get_color(rgb_dst,green_t()); p[Order::B] = get_color(rgb_dst,blue_t()); - calc_type da = p[Order::A]; - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); } } }; @@ -1722,7 +1713,7 @@ namespace agg comp_op_rgba_hue::blend_pix, comp_op_rgba_saturation::blend_pix, comp_op_rgba_color::blend_pix, - comp_op_rgba_luminosity::blend_pix, + comp_op_rgba_value::blend_pix, 0 }; @@ -1763,10 +1754,10 @@ namespace agg comp_op_hue, //----comp_op_hue comp_op_saturation, //----comp_op_saturation comp_op_color, //----comp_op_color - comp_op_luminosity, //----comp_op_luminosity + comp_op_value, //----comp_op_value end_of_comp_op_e }; - + //====================================================comp_op_adaptor_rgba template struct comp_op_adaptor_rgba { diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index cf56d3ca8..7467c95b8 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -74,7 +74,7 @@ enum composite_mode_e hue, saturation, _color, - luminosity + _value }; MAPNIK_DECL boost::optional comp_op_from_string(std::string const& name); diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 175f983d2..c11407e14 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -388,7 +388,7 @@ public: case hue: case saturation: case _color: - case luminosity: + case _value: break; } } diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 3ab87f2b2..b51968991 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -73,7 +73,7 @@ static const comp_op_lookup_type comp_lookup = boost::assign::list_of comp_op_from_string(std::string const& name) From 38f35d6f978293148243afc51e69984454a80ff4 Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Mon, 18 Jun 2012 14:41:43 -0400 Subject: [PATCH 11/11] + add missing ',' --- include/mapnik/image_compositing.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index 14f270ccd..72beac1d5 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -74,7 +74,7 @@ enum composite_mode_e hue, saturation, _color, - _value + _value, color_spin };