Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
imagefilterstransformed.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm/gm.h"
13#include "include/core/SkFont.h"
18#include "include/core/SkRect.h"
22#include "include/core/SkSize.h"
29#include "tools/DecodeUtils.h"
30#include "tools/Resources.h"
31#include "tools/ToolUtils.h"
34
35#include <utility>
36
37namespace skiagm {
38
39// This GM draws image filters with a CTM containing shearing / rotation.
40// It checks that the scale portion of the CTM is correctly extracted
41// and applied to the image inputs separately from the non-scale portion.
42
46 SkScalar radius = std::min(x, y) * 0.8f;
47
49 SkCanvas* canvas = surface->getCanvas();
50
51 canvas->clear(0x00000000);
52 SkColor colors[2];
53 colors[0] = SK_ColorWHITE;
54 colors[1] = SK_ColorBLACK;
56 paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
58 canvas->drawCircle(x, y, radius, paint);
59
60 return surface->makeImageSnapshot();
61}
62
64public:
68
69protected:
70 SkString getName() const override { return SkString("imagefilterstransformed"); }
71
72 SkISize getISize() override { return SkISize::Make(420, 240); }
73
74 void onOnceBeforeDraw() override {
75 fCheckerboard =
76 ToolUtils::create_checkerboard_image(64, 64, 0xFFA0A0A0, 0xFF404040, 8);
77 fGradientCircle = make_gradient_circle(64, 64);
78 }
79
80 void onDraw(SkCanvas* canvas) override {
81 sk_sp<SkImageFilter> gradient(SkImageFilters::Image(fGradientCircle,
85 sk_sp<SkImageFilter> filters[] = {
86 SkImageFilters::Blur(12, 0, nullptr),
87 SkImageFilters::DropShadow(0, 15, 8, 0, SK_ColorGREEN, nullptr),
89 std::move(gradient), checkerboard),
92 };
93
94 const SkScalar margin = SkIntToScalar(20);
95 const SkScalar size = SkIntToScalar(60);
96
97 for (size_t j = 0; j < 3; j++) {
98 canvas->save();
99 canvas->translate(margin, 0);
100 for (size_t i = 0; i < std::size(filters); ++i) {
102 paint.setColor(SK_ColorWHITE);
103 paint.setImageFilter(filters[i]);
104 paint.setAntiAlias(true);
105 canvas->save();
106 canvas->translate(size * SK_ScalarHalf, size * SK_ScalarHalf);
107 canvas->scale(SkDoubleToScalar(0.8), SkDoubleToScalar(0.8));
108 if (j == 1) {
109 canvas->rotate(SkIntToScalar(45));
110 } else if (j == 2) {
111 canvas->skew(SkDoubleToScalar(0.5), SkDoubleToScalar(0.2));
112 }
113 canvas->translate(-size * SK_ScalarHalf, -size * SK_ScalarHalf);
114 canvas->drawOval(SkRect::MakeXYWH(0, size * SkDoubleToScalar(0.1),
115 size, size * SkDoubleToScalar(0.6)), paint);
116 canvas->restore();
117 canvas->translate(size + margin, 0);
118 }
119 canvas->restore();
120 canvas->translate(0, size + margin);
121 }
122 }
123
124private:
125 sk_sp<SkImage> fCheckerboard;
126 sk_sp<SkImage> fGradientCircle;
127 using INHERITED = GM;
128};
129DEF_GM( return new ImageFiltersTransformedGM; )
130} // namespace skiagm
131
132//////////////////////////////////////////////////////////////////////////////
133
134DEF_SIMPLE_GM(rotate_imagefilter, canvas, 500, 500) {
136
137 const SkRect r = SkRect::MakeXYWH(50, 50, 100, 100);
138
139 sk_sp<SkImageFilter> filters[] = {
140 nullptr,
141 SkImageFilters::Blur(6, 0, nullptr),
143 };
144
145 for (auto& filter : filters) {
146 paint.setAntiAlias(false);
147 paint.setImageFilter(filter);
148
149 canvas->save();
150
151 canvas->drawRect(r, paint);
152
153 canvas->translate(150, 0);
154 canvas->save();
155 canvas->rotate(30, 100, 100);
156 canvas->drawRect(r, paint);
157 canvas->restore();
158
159 paint.setAntiAlias(true);
160 canvas->translate(150, 0);
161 canvas->save();
162 canvas->rotate(30, 100, 100);
163 canvas->drawRect(r, paint);
164 canvas->restore();
165
166 canvas->restore();
167 canvas->translate(0, 150);
168 }
169}
170
172public:
173
174 // Start at 132 degrees, since that resulted in a skipped draw before the fix to
175 // SkLocalMatrixImageFilter's computeFastBounds() function.
176 ImageFilterMatrixWLocalMatrix() : fDegrees(132.f) {}
177
178protected:
179 SkString getName() const override { return SkString("imagefilter_matrix_localmatrix"); }
180
181 SkISize getISize() override { return SkISize::Make(512, 512); }
182
183 bool onAnimate(double nanos) override {
184 // Animate the rotation angle to ensure the local matrix bounds modifications work
185 // for a variety of transformations.
186 fDegrees = TimeUtils::Scaled(1e-9f * nanos, 360.f);
187 return true;
188 }
189
190 void onOnceBeforeDraw() override {
191 fImage = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
192 }
193
194 void onDraw(SkCanvas* canvas) override {
195 SkMatrix localMatrix;
196 localMatrix.preTranslate(128, 128);
197 localMatrix.preScale(2.0f, 2.0f);
198
199 // This matrix applies a rotate around the center of the image (prior to the simulated
200 // hi-dpi 2x device scale).
201 SkMatrix filterMatrix;
202 filterMatrix.setRotate(fDegrees, 64, 64);
203
204 sk_sp<SkImageFilter> filter =
207 ->makeWithLocalMatrix(localMatrix);
208
209 SkPaint p;
210 p.setImageFilter(filter);
211 canvas->drawImage(fImage.get(), 128, 128, SkSamplingOptions(), &p);
212 }
213
214private:
215 SkScalar fDegrees;
216 sk_sp<SkImage> fImage;
217};
218
220
222public:
223
224 // Start at 70 degrees since that highlighted the issue in skbug.com/10888
225 ImageFilterComposedTransform() : fDegrees(70.f) {}
226
227protected:
228 SkString getName() const override { return SkString("imagefilter_composed_transform"); }
229
230 SkISize getISize() override { return SkISize::Make(512, 512); }
231
232 bool onAnimate(double nanos) override {
233 // Animate the rotation angle to test a variety of transformations
234 fDegrees = TimeUtils::Scaled(1e-9f * nanos, 360.f);
235 return true;
236 }
237
238 void onOnceBeforeDraw() override {
239 fImage = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
240 }
241
242 void onDraw(SkCanvas* canvas) override {
243 SkMatrix matrix = SkMatrix::RotateDeg(fDegrees);
244 // All four quadrants should render the same
245 this->drawFilter(canvas, 0.f, 0.f, this->makeDirectFilter(matrix));
246 this->drawFilter(canvas, 256.f, 0.f, this->makeEarlyComposeFilter(matrix));
247 this->drawFilter(canvas, 0.f, 256.f, this->makeLateComposeFilter(matrix));
248 this->drawFilter(canvas, 256.f, 256.f, this->makeFullComposeFilter(matrix));
249 }
250
251private:
252 SkScalar fDegrees;
253 sk_sp<SkImage> fImage;
254
255 void drawFilter(SkCanvas* canvas, SkScalar tx, SkScalar ty, sk_sp<SkImageFilter> filter) const {
256 SkPaint p;
257 p.setImageFilter(std::move(filter));
258
259 canvas->save();
260 canvas->translate(tx, ty);
261 canvas->clipRect(SkRect::MakeWH(256, 256));
262 canvas->scale(0.5f, 0.5f);
263 canvas->translate(128, 128);
264 canvas->drawImage(fImage, 0, 0, SkSamplingOptions(SkFilterMode::kLinear), &p);
265 canvas->restore();
266 }
267
268 // offset(matrix(offset))
269 sk_sp<SkImageFilter> makeDirectFilter(const SkMatrix& matrix) const {
270 SkPoint v = {fImage->width() / 2.f, fImage->height() / 2.f};
271 sk_sp<SkImageFilter> filter = SkImageFilters::Offset(-v.fX, -v.fY, nullptr);
273 std::move(filter));
274 filter = SkImageFilters::Offset(v.fX, v.fY, std::move(filter));
275 return filter;
276 }
277
278 // offset(compose(matrix, offset))
279 sk_sp<SkImageFilter> makeEarlyComposeFilter(const SkMatrix& matrix) const {
280 SkPoint v = {fImage->width() / 2.f, fImage->height() / 2.f};
283 matrix, SkSamplingOptions(SkFilterMode::kLinear), nullptr);
284 filter = SkImageFilters::Compose(std::move(filter), std::move(offset));
285 filter = SkImageFilters::Offset(v.fX, v.fY, std::move(filter));
286 return filter;
287 }
288
289 // compose(offset, matrix(offset))
290 sk_sp<SkImageFilter> makeLateComposeFilter(const SkMatrix& matrix) const {
291 SkPoint v = {fImage->width() / 2.f, fImage->height() / 2.f};
292 sk_sp<SkImageFilter> filter = SkImageFilters::Offset(-v.fX, -v.fY, nullptr);
294 std::move(filter));
296 filter = SkImageFilters::Compose(std::move(offset), std::move(filter));
297 return filter;
298 }
299
300 // compose(offset, compose(matrix, offset))
301 sk_sp<SkImageFilter> makeFullComposeFilter(const SkMatrix& matrix) const {
302 SkPoint v = {fImage->width() / 2.f, fImage->height() / 2.f};
305 matrix, SkSamplingOptions(SkFilterMode::kLinear), nullptr);
306 filter = SkImageFilters::Compose(std::move(filter), std::move(offset));
307 offset = SkImageFilters::Offset(v.fX, v.fY, nullptr);
308 filter = SkImageFilters::Compose(std::move(offset), std::move(filter));
309 return filter;
310 }
311};
312
314
315// Tests SkImageFilters::Image under tricky matrices (mirrors and perspective)
316DEF_SIMPLE_GM(imagefilter_transformed_image, canvas, 256, 256) {
317 sk_sp<SkImage> image = ToolUtils::GetResourceAsImage("images/color_wheel.png");
319
320 const SkRect imageRect = SkRect::MakeIWH(image->width(), image->height());
321
322 SkM44 m1 = SkM44::Translate(0.9f * image->width(), 0.1f * image->height()) *
323 SkM44::Scale(-.8f, .8f);
324
325 SkM44 m2 = SkM44::RectToRect({-1.f, -1.f, 1.f, 1.f}, imageRect) *
326 SkM44::Perspective(0.01f, 100.f, SK_ScalarPI / 3.f) *
327 SkM44::Translate(0.f, 0.f, -2.f) *
328 SkM44::Rotate({0.f, 1.f, 0.f}, SK_ScalarPI / 6.f) *
329 SkM44::RectToRect(imageRect, {-1.f, -1.f, 1.f, 1.f});
330
332 canvas->drawString("Columns should match", 5.f, 15.f, font, SkPaint());
333 canvas->translate(0.f, 10.f);
334
336 for (auto m : {m1, m2}) {
337 canvas->save();
338 for (bool canvasTransform : {false, true}) {
339 canvas->save();
340 canvas->clipRect(imageRect);
341
342 sk_sp<SkImageFilter> finalFilter;
343 if (canvasTransform) {
344 canvas->concat(m);
345 finalFilter = imageFilter;
346 } else {
347 finalFilter = SkImageFilters::MatrixTransform(m.asM33(), sampling, imageFilter);
348 }
349
351 paint.setImageFilter(std::move(finalFilter));
352 canvas->drawPaint(paint);
353
354 canvas->restore();
355 canvas->translate(image->width(), 0.f);
356 }
357 canvas->restore();
358
359 canvas->translate(0.f, image->height());
360 }
361}
@ kSrcOver
r = s + (1-sa)*d
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
#define SK_ScalarHalf
Definition SkScalar.h:19
#define SkDoubleToScalar(x)
Definition SkScalar.h:64
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define SK_ScalarPI
Definition SkScalar.h:21
bool onAnimate(double nanos) override
void onDraw(SkCanvas *canvas) override
void onDraw(SkCanvas *canvas) override
bool onAnimate(double nanos) override
void drawOval(const SkRect &oval, const SkPaint &paint)
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
void drawPaint(const SkPaint &paint)
void clear(SkColor color)
Definition SkCanvas.h:1199
void rotate(SkScalar degrees)
int save()
Definition SkCanvas.cpp:451
void scale(SkScalar sx, SkScalar sy)
void concat(const SkMatrix &matrix)
void drawString(const char str[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition SkCanvas.h:1803
void skew(SkScalar sx, SkScalar sy)
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition SkCanvas.h:1528
void drawCircle(SkScalar cx, SkScalar cy, SkScalar radius, const SkPaint &paint)
static sk_sp< SkShader > MakeRadial(const SkPoint &center, SkScalar radius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
sk_sp< SkImageFilter > makeWithLocalMatrix(const SkMatrix &matrix) const
static sk_sp< SkImageFilter > DropShadow(SkScalar dx, SkScalar dy, SkScalar sigmaX, SkScalar sigmaY, SkColor color, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Erode(SkScalar radiusX, SkScalar radiusY, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Blur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > DisplacementMap(SkColorChannel xChannelSelector, SkColorChannel yChannelSelector, SkScalar scale, sk_sp< SkImageFilter > displacement, sk_sp< SkImageFilter > color, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Compose(sk_sp< SkImageFilter > outer, sk_sp< SkImageFilter > inner)
static sk_sp< SkImageFilter > Image(sk_sp< SkImage > image, const SkRect &srcRect, const SkRect &dstRect, const SkSamplingOptions &sampling)
static sk_sp< SkImageFilter > MatrixTransform(const SkMatrix &matrix, const SkSamplingOptions &sampling, sk_sp< SkImageFilter > input)
static sk_sp< SkImageFilter > Blend(SkBlendMode mode, sk_sp< SkImageFilter > background, sk_sp< SkImageFilter > foreground=nullptr, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Offset(SkScalar dx, SkScalar dy, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
static sk_sp< SkImageFilter > Dilate(SkScalar radiusX, SkScalar radiusY, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
int width() const
Definition SkImage.h:285
int height() const
Definition SkImage.h:291
Definition SkM44.h:150
static SkM44 Rotate(SkV3 axis, SkScalar radians)
Definition SkM44.h:239
static SkM44 RectToRect(const SkRect &src, const SkRect &dst)
Definition SkM44.cpp:304
static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z=0)
Definition SkM44.h:225
static SkM44 Perspective(float near, float far, float angle)
Definition SkM44.cpp:343
static SkM44 Scale(SkScalar x, SkScalar y, SkScalar z=1)
Definition SkM44.h:232
static SkMatrix RotateDeg(SkScalar deg)
Definition SkMatrix.h:104
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:452
SkMatrix & preTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:263
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:315
T * get() const
Definition SkRefCnt.h:303
void setBGColor(SkColor)
Definition gm.cpp:159
void onDraw(SkCanvas *canvas) override
const Paint & paint
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
#define DEF_GM(CODE)
Definition gm.h:40
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
Definition gm.h:50
double y
double x
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
static float Scaled(float time, float speed, float period=0)
Definition TimeUtils.h:27
SkFont DefaultPortableFont()
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition DecodeUtils.h:25
sk_sp< SkImage > create_checkerboard_image(int w, int h, SkColor c1, SkColor c2, int checkSize)
static sk_sp< SkImage > make_gradient_circle(int width, int height)
int32_t height
int32_t width
Point offset
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
float fX
x-axis value
static constexpr SkPoint Make(float x, float y)
float fY
y-axis value
static SkRect MakeIWH(int w, int h)
Definition SkRect.h:623
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609
static void checkerboard(SkCanvas *canvas, SkColor c1, SkColor c2, int size)