start implementing hsla image-filter

This commit is contained in:
Dane Springmeyer 2013-02-26 19:21:05 -05:00
parent 70940088d7
commit f5d5502bc4
3 changed files with 179 additions and 0 deletions

View file

@ -26,6 +26,7 @@
//mapnik //mapnik
#include <mapnik/image_filter_types.hpp> #include <mapnik/image_filter_types.hpp>
#include <mapnik/util/hsl.hpp>
// boost // boost
#include <boost/variant/static_visitor.hpp> #include <boost/variant/static_visitor.hpp>
@ -403,6 +404,69 @@ void apply_filter(Src & src, agg_stack_blur const& op)
agg::stack_blur_rgba32(pixf,op.rx,op.ry); agg::stack_blur_rgba32(pixf,op.rx,op.ry);
} }
template <typename Src>
void apply_filter(Src & src, hsla const& op)
{
using namespace boost::gil;
Tinter tint;
tint.h0 = .1;
tint.s0 = .3;
tint.l1 = .9;
bool tinting = !tint.is_identity();
bool set_alpha = !tint.is_alpha_identity();
// todo - should filters be able to report if they should be run?
if (tinting || set_alpha)
{
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)
{
uint8_t & a = get_color(src_it[x], alpha_t());
uint8_t a_original = a;
if (set_alpha)
{
double a2 = tint.a0 + (a/255.0 * (tint.a1 - tint.a0));
if (a2 > 1) a2 = 1;
if (a2 < 0) a2 = 0;
a = static_cast<unsigned>(std::floor(a2 * 255.0));
}
if (a > 1 && tinting)
{
double h;
double s;
double l;
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());
// demultiply
r /= a_original;
g /= a_original;
b /= a_original;
rgb2hsl(r,g,b,h,s,l);
double h2 = tint.h0 + (h * (tint.h1 - tint.h0));
double s2 = tint.s0 + (s * (tint.s1 - tint.s0));
double l2 = tint.l0 + (l * (tint.l1 - tint.l0));
if (h2 > 1) h2 = 1;
if (h2 < 0) h2 = 0;
if (s2 > 1) s2 = 1;
if (s2 < 0) s2 = 0;
if (l2 > 1) l2 = 1;
if (l2 < 0) l2 = 0;
hsl2rgb(h2,s2,l2,r,g,b);
// premultiply
// we only work with premultiplied source,
// thus all color values must be <= alpha
r *= a;
g *= a;
b *= a;
}
}
}
}
}
template <typename Src> template <typename Src>
void apply_filter(Src & src, gray const& op) void apply_filter(Src & src, gray const& op)
{ {

View file

@ -55,6 +55,13 @@ struct agg_stack_blur
unsigned ry; unsigned ry;
}; };
struct hsla
{
hsla(std::string const& tinter)
: tinter_(tinter) {}
std::string tinter_;
};
typedef boost::variant<filter::blur, typedef boost::variant<filter::blur,
filter::gray, filter::gray,
filter::agg_stack_blur, filter::agg_stack_blur,

108
include/mapnik/util/hsl.hpp Normal file
View file

@ -0,0 +1,108 @@
/*****************************************************************************
*
* 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_HSL_HPP
#define MAPNIK_HSL_HPP
#include <cmath>
namespace mapnik {
struct Tinter {
double h0;
double h1;
double s0;
double s1;
double l0;
double l1;
double a0;
double a1;
Tinter() :
h0(0),
h1(1),
s0(0),
s1(1),
l0(0),
l1(1),
a0(0),
a1(1) { }
bool is_identity() {
return (h0 == 0 &&
h1 == 1 &&
s0 == 0 &&
s1 == 1 &&
l0 == 0 &&
l1 == 1);
}
bool is_alpha_identity() {
return (a0 == 0 &&
a1 == 1);
}
};
static inline void rgb2hsl(unsigned char red, unsigned char green, unsigned char blue,
double & h, double & s, double & l) {
double r = red/255.0;
double g = green/255.0;
double b = blue/255.0;
double max = std::max(r,std::max(g,b));
double min = std::min(r,std::min(g,b));
double delta = max - min;
double gamma = max + min;
h = s = l = gamma / 2.0;
if (delta > 0.0) {
s = l > 0.5 ? delta / (2.0 - gamma) : delta / gamma;
if (max == r && max != g) h = (g - b) / delta + (g < b ? 6.0 : 0.0);
else if (max == g && max != b) h = (b - r) / delta + 2.0;
else if (max == b && max != r) h = (r - g) / delta + 4.0;
h /= 6.0;
}
}
static inline double hueToRGB(double m1, double m2, double h) {
// poor mans fmod
if(h < 0) h += 1;
if(h > 1) h -= 1;
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
if (h * 2 < 1) return m2;
if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
return m1;
}
static inline void hsl2rgb(double h, double s, double l,
unsigned char & r, unsigned char & g, unsigned char & b) {
if (!s) {
r = g = b = static_cast<unsigned char>(l * 255);
}
double m2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
double m1 = l * 2 - m2;
r = static_cast<unsigned char>(hueToRGB(m1, m2, h + 0.33333) * 255);
g = static_cast<unsigned char>(hueToRGB(m1, m2, h) * 255);
b = static_cast<unsigned char>(hueToRGB(m1, m2, h - 0.33333) * 255);
}
}
#endif // end MAPNIK_HSL_HPP