Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
nr-filter-colormatrix.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * feColorMatrix filter primitive renderer
4 *
5 * Authors:
6 * Felipe CorrĂȘa da Silva Sanches <juca@members.fsf.org>
7 * Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
8 *
9 * Copyright (C) 2007 authors
10 *
11 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
12 */
13
14#include <cmath>
15#include <algorithm>
17#include "display/cairo-utils.h"
20#include <2geom/math-utils.h>
21
22namespace Inkscape {
23namespace Filters {
24
26
28
30{
31 unsigned limit = std::min(static_cast<size_t>(20), values.size());
32 for (unsigned i = 0; i < limit; ++i) {
33 if (i % 5 == 4) {
34 _v[i] = round(values[i]*255*255);
35 } else {
36 _v[i] = round(values[i]*255);
37 }
38 }
39 for (unsigned i = limit; i < 20; ++i) {
40 _v[i] = (i % 6 == 0) ? 255 : 0;
41 }
42}
43
45{
46 EXTRACT_ARGB32(in, a, r, g, b)
47 // we need to un-premultiply alpha values for this type of matrix
48 // TODO: unpremul can be ignored if there is an identity mapping on the alpha channel
49 if (a != 0) {
50 r = unpremul_alpha(r, a);
51 g = unpremul_alpha(g, a);
52 b = unpremul_alpha(b, a);
53 }
54
55 gint32 ro = r*_v[0] + g*_v[1] + b*_v[2] + a*_v[3] + _v[4];
56 gint32 go = r*_v[5] + g*_v[6] + b*_v[7] + a*_v[8] + _v[9];
57 gint32 bo = r*_v[10] + g*_v[11] + b*_v[12] + a*_v[13] + _v[14];
58 gint32 ao = r*_v[15] + g*_v[16] + b*_v[17] + a*_v[18] + _v[19];
59 ro = (pxclamp(ro, 0, 255*255) + 127) / 255;
60 go = (pxclamp(go, 0, 255*255) + 127) / 255;
61 bo = (pxclamp(bo, 0, 255*255) + 127) / 255;
62 ao = (pxclamp(ao, 0, 255*255) + 127) / 255;
63
64 ro = premul_alpha(ro, ao);
65 go = premul_alpha(go, ao);
66 bo = premul_alpha(bo, ao);
67
68 ASSEMBLE_ARGB32(pxout, ao, ro, go, bo)
69 return pxout;
70}
71
72struct ColorMatrixSaturate
73{
74 ColorMatrixSaturate(double v_in)
75 {
76 // clamp parameter instead of clamping color values
77 double v = std::clamp(v_in, 0.0, 1.0);
78 _v[0] = 0.213+0.787*v; _v[1] = 0.715-0.715*v; _v[2] = 0.072-0.072*v;
79 _v[3] = 0.213-0.213*v; _v[4] = 0.715+0.285*v; _v[5] = 0.072-0.072*v;
80 _v[6] = 0.213-0.213*v; _v[7] = 0.715-0.715*v; _v[8] = 0.072+0.928*v;
81 }
82
83 guint32 operator()(guint32 in)
84 {
85 EXTRACT_ARGB32(in, a, r, g, b)
86
87 // Note: this cannot be done in fixed point, because the loss of precision
88 // causes overflow for some values of v
89 guint32 ro = r*_v[0] + g*_v[1] + b*_v[2] + 0.5;
90 guint32 go = r*_v[3] + g*_v[4] + b*_v[5] + 0.5;
91 guint32 bo = r*_v[6] + g*_v[7] + b*_v[8] + 0.5;
92
93 ASSEMBLE_ARGB32(pxout, a, ro, go, bo)
94 return pxout;
95 }
96
97private:
98 double _v[9];
99};
100
101struct ColorMatrixHueRotate
102{
103 ColorMatrixHueRotate(double v)
104 {
105 double sinhue, coshue;
106 Geom::sincos(v * M_PI/180.0, sinhue, coshue);
107
108 _v[0] = std::round((0.213 +0.787*coshue -0.213*sinhue)*255);
109 _v[1] = std::round((0.715 -0.715*coshue -0.715*sinhue)*255);
110 _v[2] = std::round((0.072 -0.072*coshue +0.928*sinhue)*255);
111
112 _v[3] = std::round((0.213 -0.213*coshue +0.143*sinhue)*255);
113 _v[4] = std::round((0.715 +0.285*coshue +0.140*sinhue)*255);
114 _v[5] = std::round((0.072 -0.072*coshue -0.283*sinhue)*255);
115
116 _v[6] = std::round((0.213 -0.213*coshue -0.787*sinhue)*255);
117 _v[7] = std::round((0.715 -0.715*coshue +0.715*sinhue)*255);
118 _v[8] = std::round((0.072 +0.928*coshue +0.072*sinhue)*255);
119 }
120
121 guint32 operator()(guint32 in)
122 {
123 EXTRACT_ARGB32(in, a, r, g, b)
124 gint32 maxpx = a*255;
125 gint32 ro = r*_v[0] + g*_v[1] + b*_v[2];
126 gint32 go = r*_v[3] + g*_v[4] + b*_v[5];
127 gint32 bo = r*_v[6] + g*_v[7] + b*_v[8];
128 ro = (pxclamp(ro, 0, maxpx) + 127) / 255;
129 go = (pxclamp(go, 0, maxpx) + 127) / 255;
130 bo = (pxclamp(bo, 0, maxpx) + 127) / 255;
131
132 ASSEMBLE_ARGB32(pxout, a, ro, go, bo)
133 return pxout;
134 }
135
136private:
137 gint32 _v[9];
138};
139
140struct ColorMatrixLuminanceToAlpha
141{
142 guint32 operator()(guint32 in)
143 {
144 // original computation in double: r*0.2125 + g*0.7154 + b*0.0721
145 EXTRACT_ARGB32(in, a, r, g, b)
146 // unpremultiply color values
147 if (a != 0) {
148 r = unpremul_alpha(r, a);
149 g = unpremul_alpha(g, a);
150 b = unpremul_alpha(b, a);
151 }
152 guint32 ao = r*54 + g*182 + b*18;
153 return ((ao + 127) / 255) << 24;
154 }
155};
156
158{
159 cairo_surface_t *input = slot.getcairo(_input);
160 cairo_surface_t *out = nullptr;
161
162 // We may need to transform input surface to correct color interpolation space. The input surface
163 // might be used as input to another primitive but it is likely that all the primitives in a given
164 // filter use the same color interpolation space so we don't copy the input before converting.
166
168 out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_ALPHA);
169 } else {
170 out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA);
171 // Set ci to that used for computation
173 }
174
175 switch (type) {
178 break;
180 ink_cairo_surface_filter(input, out, ColorMatrixSaturate(value));
181 break;
183 ink_cairo_surface_filter(input, out, ColorMatrixHueRotate(value));
184 break;
186 ink_cairo_surface_filter(input, out, ColorMatrixLuminanceToAlpha());
187 break;
189 default:
190 break;
191 }
192
193 slot.set(_output, out);
194 cairo_surface_destroy(out);
195}
196
198{
199 return true;
200}
201
203{
204 return 2.0;
205}
206
211
213{
214 value = v;
215}
216
217void FilterColorMatrix::set_values(std::vector<double> const &v)
218{
219 values = v;
220}
221
222} // namespace Filters
223} // namespace Inkscape
224
225/*
226 Local Variables:
227 mode:c++
228 c-file-style:"stroustrup"
229 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
230 indent-tabs-mode:nil
231 fill-column:99
232 End:
233*/
234// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Cairo software blending templates.
G_GNUC_CONST gint32 pxclamp(gint32 v, gint32 low, gint32 high)
void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter &&filter)
cairo_surface_t * ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c)
void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci)
Set the color_interpolation_value for a Cairo surface.
Cairo integration helpers.
G_GNUC_CONST guint32 premul_alpha(const guint32 color, const guint32 alpha)
G_GNUC_CONST guint32 unpremul_alpha(const guint32 color, const guint32 alpha)
3x3 matrix representing an affine transformation.
Definition affine.h:70
bool can_handle_affine(Geom::Affine const &) const override
Indicate whether the filter primitive can handle the given affine.
virtual void set_values(std::vector< double > const &values)
virtual void set_type(FilterColorMatrixType type)
double complexity(Geom::Affine const &ctm) const override
void render_cairo(FilterSlot &slot) const override
cairo_surface_t * getcairo(int slot)
Returns the pixblock in specified slot.
void set(int slot, cairo_surface_t *s)
Sets or re-sets the pixblock associated with given slot.
unsigned int guint32
struct _cairo_surface cairo_surface_t
Low level math functions and compatibility wrappers.
void sincos(double angle, double &sin_, double &cos_)
Simultaneously compute a sine and a cosine of the same angle.
Definition math-utils.h:89
Helper class to stream background task notifications as a series of messages.
signed int gint32