Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
nr-filter-image.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * feImage filter primitive renderer
4 *
5 * Authors:
6 * Felipe CorrĂȘa da Silva Sanches <juca@members.fsf.org>
7 * Tavmjong Bah <tavmjong@free.fr>
8 * Abhishek Sharma
9 *
10 * Copyright (C) 2007-2011 authors
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14#include "nr-filter-image.h"
15
16#include "cairo-utils.h"
17#include "enums.h"
18
19// Drawing
20#include "drawing-context.h"
21#include "drawing-item.h"
22#include "nr-filter-slot.h"
23#include "nr-filter-units.h"
24#include "nr-filter.h"
25
26namespace Inkscape {
27namespace Filters {
28
30{
31 if (!item) {
32 return;
33 }
34
35 item->update();
36}
37
39{
40 if (!item) {
41 return;
42 }
43
44 Geom::OptRect area = item->drawbox();
45 if (!area) {
46 return;
47 }
48
49 // Viewport is filter primitive area (in user coordinates).
50 // Note: viewport calculation in non-trivial. Do not rely
51 // on get_matrix_primitiveunits2pb().
53 slot.set_primitive_area(_output, vp); // Needed for tiling
54
55 double feImageX = vp.left();
56 double feImageY = vp.top();
57 double feImageWidth = vp.width();
58 double feImageHeight = vp.height();
59
60 // feImage is suppose to use the same parameters as a normal SVG image.
61 // If a width or height is set to zero, the image is not suppose to be displayed.
62 // This does not seem to be what Firefox or Opera does, nor does the W3C displacement
63 // filter test expect this behavior. If the width and/or height are zero, we use
64 // the width and height of the object bounding box.
66 Geom::Point bbox_00 = Geom::Point(0,0) * m;
67 Geom::Point bbox_w0 = Geom::Point(1,0) * m;
68 Geom::Point bbox_0h = Geom::Point(0,1) * m;
69 double bbox_width = Geom::distance(bbox_00, bbox_w0);
70 double bbox_height = Geom::distance(bbox_00, bbox_0h);
71
72 if (feImageWidth == 0) feImageWidth = bbox_width;
73 if (feImageHeight == 0) feImageHeight = bbox_height;
74
75 int device_scale = slot.get_device_scale();
76
77 Geom::Rect sa = slot.get_slot_area();
78 cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sa.width() * device_scale, sa.height() * device_scale);
79 cairo_surface_set_device_scale(out, device_scale, device_scale);
80
81 Inkscape::DrawingContext dc(out, sa.min());
82 Geom::Affine user2pb = slot.get_units().get_matrix_user2pb();
83 dc.transform(user2pb); // we are now in primitive units
84
85 Geom::IntRect render_rect = area->roundOutwards();
86
87 // Internal image, like <use>
88 if (from_element) {
89 dc.translate(feImageX, feImageY);
90 item->render(dc, slot.get_rendercontext(), render_rect);
91
92 // For the moment, we'll assume that any image is in sRGB color space
94 } else {
95 // For the moment, we'll assume that any image is in sRGB color space
96 // set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB);
97 // This seemed like a sensible thing to do but it breaks filters-displace-01-f.svg
98
99 // Now that we have the viewport, we must map image inside.
100 // Partially copied from sp-image.cpp.
101
102 auto image_width = area->width();
103 auto image_height = area->height();
104
105 // Do nothing if preserveAspectRatio is "none".
107
108 // Check aspect ratio of image vs. viewport
109 double feAspect = feImageHeight / feImageWidth;
110 double aspect = (double)image_height / image_width;
111 bool ratio = feAspect < aspect;
112
113 double ax, ay; // Align side
114 switch (aspect_align) {
116 ax = 0.0;
117 ay = 0.0;
118 break;
120 ax = 0.5;
121 ay = 0.0;
122 break;
124 ax = 1.0;
125 ay = 0.0;
126 break;
128 ax = 0.0;
129 ay = 0.5;
130 break;
132 ax = 0.5;
133 ay = 0.5;
134 break;
136 ax = 1.0;
137 ay = 0.5;
138 break;
140 ax = 0.0;
141 ay = 1.0;
142 break;
144 ax = 0.5;
145 ay = 1.0;
146 break;
148 ax = 1.0;
149 ay = 1.0;
150 break;
151 default:
152 ax = 0.0;
153 ay = 0.0;
154 break;
155 }
156
158 // image clipped by viewbox
159
160 if (ratio) {
161 // clip top/bottom
162 feImageY -= ay * (feImageWidth * aspect - feImageHeight);
163 feImageHeight = feImageWidth * aspect;
164 } else {
165 // clip sides
166 feImageX -= ax * (feImageHeight / aspect - feImageWidth);
167 feImageWidth = feImageHeight / aspect;
168 }
169
170 } else {
171 // image fits into viewbox
172
173 if (ratio) {
174 // fit to height
175 feImageX += ax * (feImageWidth - feImageHeight / aspect );
176 feImageWidth = feImageHeight / aspect;
177 } else {
178 // fit to width
179 feImageY += ay * (feImageHeight - feImageWidth * aspect);
180 feImageHeight = feImageWidth * aspect;
181 }
182 }
183 }
184
185 double scaleX = feImageWidth / image_width;
186 double scaleY = feImageHeight / image_height;
187
188 dc.translate(feImageX, feImageY);
189 dc.scale(scaleX, scaleY);
190 item->render(dc, slot.get_rendercontext(), render_rect);
191 }
192
193 slot.set(_output, out);
194 cairo_surface_destroy(out);
195}
196
198{
199 return true;
200}
201
203{
204 // TODO: right now we cannot actually measure this in any meaningful way.
205 return 1.1;
206}
207
208void FilterImage::set_align(unsigned align)
209{
210 aspect_align = align;
211}
212
214{
216}
217
218} // namespace Filters
219} // namespace Inkscape
220
221/*
222 Local Variables:
223 mode:c++
224 c-file-style:"stroustrup"
225 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
226 indent-tabs-mode:nil
227 fill-column:99
228 End:
229*/
230// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci)
Set the color_interpolation_value for a Cairo surface.
Cairo integration helpers.
3x3 matrix representing an affine transformation.
Definition affine.h:70
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
Axis aligned, non-empty, generic rectangle.
C top() const
Return top coordinate of the rectangle (+Y is downwards).
C left() const
Return leftmost coordinate of the rectangle (+X is to the right).
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
Axis-aligned rectangle that can be empty.
Definition rect.h:203
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
Minimal wrapper over Cairo.
void scale(Geom::Scale const &s)
void transform(Geom::Affine const &trans)
void translate(Geom::Point const &t)
unsigned render(DrawingContext &dc, RenderContext &rc, Geom::IntRect const &area, unsigned flags=0, DrawingItem const *stop_at=nullptr) const
Rasterize items.
Geom::OptIntRect const & drawbox() const
void update(Geom::IntRect const &area=Geom::IntRect::infinite(), UpdateContext const &ctx=UpdateContext(), unsigned flags=STATE_ALL, unsigned reset=0)
Update derived data before operations.
bool can_handle_affine(Geom::Affine const &) const override
Indicate whether the filter primitive can handle the given affine.
Inkscape::DrawingItem * item
double complexity(Geom::Affine const &ctm) const override
void render_cairo(FilterSlot &slot) const override
Geom::Rect filter_primitive_area(FilterUnits const &units) const
Returns the filter primitive area in user coordinate system.
void set_primitive_area(int slot, Geom::Rect &area)
void set(int slot, cairo_surface_t *s)
Sets or re-sets the pixblock associated with given slot.
int get_device_scale() const
Gets the device scale; for high DPI monitors.
RenderContext & get_rendercontext() const
FilterUnits const & get_units() const
Geom::Affine get_matrix_user2filterunits() const
Gets the user coordinates to filterUnits transformation matrix.
Geom::Affine get_matrix_user2pb() const
Gets the user coordinates to pixblock coordinates transformation matrix.
Cairo drawing context with Inkscape extensions.
Canvas item belonging to an SVG drawing element.
struct _cairo_surface cairo_surface_t
@ SP_ASPECT_XMAX_YMIN
Definition enums.h:45
@ SP_ASPECT_XMID_YMIN
Definition enums.h:44
@ SP_ASPECT_XMIN_YMID
Definition enums.h:46
@ SP_ASPECT_XMIN_YMAX
Definition enums.h:49
@ SP_ASPECT_XMAX_YMID
Definition enums.h:48
@ SP_ASPECT_XMID_YMAX
Definition enums.h:50
@ SP_ASPECT_NONE
Definition enums.h:42
@ SP_ASPECT_XMIN_YMIN
Definition enums.h:43
@ SP_ASPECT_XMAX_YMAX
Definition enums.h:51
@ SP_ASPECT_XMID_YMID
Definition enums.h:47
@ SP_ASPECT_SLICE
Definition enums.h:56
Angle distance(Angle const &a, Angle const &b)
Definition angle.h:163
Helper class to stream background task notifications as a series of messages.
static T clip(T const &v, T const &a, T const &b)
@ SP_CSS_COLOR_INTERPOLATION_SRGB