xref: /aosp_15_r20/external/skia/gm/imagefilterscropexpand.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 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"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorFilter.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkImageFilter.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkPoint.h"
17 #include "include/core/SkPoint3.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkScalar.h"
21 #include "include/core/SkShader.h"
22 #include "include/core/SkSurface.h"
23 #include "include/core/SkTileMode.h"
24 #include "include/effects/SkGradientShader.h"
25 #include "include/effects/SkImageFilters.h"
26 
27 #include <utility>
28 
29 namespace {
30 
31 sk_sp<SkImage> make_checkerboard();
32 sk_sp<SkImage> make_gradient_circle(int width, int height);
33 void draw(SkCanvas*, sk_sp<SkImage>, const SkIRect&, sk_sp<SkImageFilter>);
34 
35 }  // namespace
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 
39 DEF_SIMPLE_GM(imagefilterscropexpand, canvas, 730, 650) {
40     SkIRect cropRect = SkIRect::MakeXYWH(10, 10, 44, 44);
41 
42     sk_sp<SkImage> gradientCircle(make_gradient_circle(64, 64));
43     auto checkerboard = make_checkerboard();
44 
45     sk_sp<SkImageFilter> gradientCircleSource(SkImageFilters::Image(std::move(gradientCircle),
46                                                                     SkFilterMode::kLinear));
47     sk_sp<SkImageFilter> noopCropped(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
48     // This color matrix saturates the green component but only partly increases the opacity.
49     // For the opaque checkerboard, the opacity boost doesn't matter but it does impact the
50     // area outside the checkerboard.
51     float matrix[20] = { 1, 0, 0, 0, 0,
52                          0, 1, 0, 0, 1,
53                          0, 0, 1, 0, 0,
54                          0, 0, 0, 1, 32.0f/255 };
55     sk_sp<SkColorFilter> cfAlphaTrans(SkColorFilters::Matrix(matrix));
56 
57     SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
58     SkScalar MARGIN = SkIntToScalar(12);
59 
60     SkPoint3 pointLocation = SkPoint3::Make(0, 0, SkIntToScalar(10));
61     SkScalar kd = SkIntToScalar(2);
62     SkScalar surfaceScale = SkIntToScalar(1);
63     SkIRect bounds;
64     r.roundOut(&bounds);
65 
66     SkPaint paint;
67     canvas->translate(MARGIN, MARGIN);
68     for (int outset = -15; outset <= 20; outset += 5) {
69         canvas->save();
70         SkIRect bigRect = cropRect;
71         bigRect.outset(outset, outset);
72 
73         draw(canvas, checkerboard, bigRect,
74              SkImageFilters::ColorFilter(cfAlphaTrans, noopCropped,  &bigRect));
75 
76         draw(canvas, checkerboard, bigRect,
77              SkImageFilters::Blur(0.3f, 0.3f,  noopCropped, &bigRect));
78 
79         draw(canvas, checkerboard, bigRect,
80              SkImageFilters::Blur(8.0f, 8.0f,  noopCropped, &bigRect));
81 
82         draw(canvas, checkerboard, bigRect,
83              SkImageFilters::Dilate(2, 2, noopCropped, &bigRect));
84 
85         draw(canvas, checkerboard, bigRect,
86              SkImageFilters::Erode(2, 2, noopCropped, &bigRect));
87 
88         draw(canvas, checkerboard, bigRect,
89              SkImageFilters::DropShadow(10, 10, 3, 3, SK_ColorBLUE, noopCropped, &bigRect));
90 
91         draw(canvas, checkerboard, bigRect,
92              SkImageFilters::DisplacementMap(SkColorChannel::kR, SkColorChannel::kR, 12,
93                                              gradientCircleSource, noopCropped, &bigRect));
94 
95         draw(canvas, checkerboard, bigRect,
96              SkImageFilters::Offset(SkIntToScalar(-8), SkIntToScalar(16), noopCropped, &bigRect));
97 
98         draw(canvas, checkerboard, bigRect,
99              SkImageFilters::PointLitDiffuse(pointLocation, SK_ColorWHITE, surfaceScale, kd,
100                                              noopCropped, &bigRect));
101 
102         canvas->restore();
103         canvas->translate(0, SkIntToScalar(80));
104     }
105 }
106 
107 namespace {
make_checkerboard()108     sk_sp<SkImage> make_checkerboard() {
109         auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(64, 64));
110         auto canvas = surf->getCanvas();
111         canvas->clear(0xFFFF0000);
112         SkPaint darkPaint;
113         darkPaint.setColor(0xFF404040);
114         SkPaint lightPaint;
115         lightPaint.setColor(0xFFA0A0A0);
116         for (int y = 8; y < 48; y += 16) {
117             for (int x = 8; x < 48; x += 16) {
118                 canvas->save();
119                 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
120                 canvas->drawRect(SkRect::MakeXYWH(0, 0, 8, 8), darkPaint);
121                 canvas->drawRect(SkRect::MakeXYWH(8, 0, 8, 8), lightPaint);
122                 canvas->drawRect(SkRect::MakeXYWH(0, 8, 8, 8), lightPaint);
123                 canvas->drawRect(SkRect::MakeXYWH(8, 8, 8, 8), darkPaint);
124                 canvas->restore();
125             }
126         }
127         return surf->makeImageSnapshot();
128     }
129 
make_gradient_circle(int width,int height)130     sk_sp<SkImage> make_gradient_circle(int width, int height) {
131         SkScalar x = SkIntToScalar(width / 2);
132         SkScalar y = SkIntToScalar(height / 2);
133         SkScalar radius = std::min(x, y) * 0.8f;
134         auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(width, height)));
135         SkCanvas* canvas = surface->getCanvas();
136         canvas->clear(0x00000000);
137         SkColor colors[2];
138         colors[0] = SK_ColorWHITE;
139         colors[1] = SK_ColorBLACK;
140         SkPaint paint;
141         paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr,
142                                                      2, SkTileMode::kClamp));
143         canvas->drawCircle(x, y, radius, paint);
144 
145         return surface->makeImageSnapshot();
146     }
147 
draw(SkCanvas * canvas,sk_sp<SkImage> image,const SkIRect & layerRect,sk_sp<SkImageFilter> filter)148     void draw(SkCanvas* canvas, sk_sp<SkImage> image, const SkIRect& layerRect,
149                      sk_sp<SkImageFilter> filter) {
150           SkPaint paint;
151           paint.setImageFilter(std::move(filter));
152 
153           // We don't pass 'layerRect' in as the saveLayer bounds hint because that is not the
154           // pre-filtering local bounds (which would be image->dimensions()). We could clip before
155           // the saveLayer but every 'filter' should have been constructed with a crop rect equal
156           // to 'layerRect', so do an unclipped saveLayer to ensure that the crop rect itself is
157           // what restricts the output of the filter.
158           canvas->saveLayer(nullptr, &paint);
159           canvas->drawImage(image, 0, 0);
160           canvas->restore();
161 
162           SkPaint strokePaint;
163           strokePaint.setColor(0xFFFF0000);
164           strokePaint.setStyle(SkPaint::kStroke_Style);
165           canvas->drawRect(SkRect::Make(layerRect), strokePaint);
166 
167           canvas->translate(SkIntToScalar(80), 0);
168     }
169 }  // namespace
170