start implementing hsla image-filter
This commit is contained in:
parent
70940088d7
commit
f5d5502bc4
3 changed files with 179 additions and 0 deletions
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
108
include/mapnik/util/hsl.hpp
Normal 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
|
Loading…
Reference in a new issue