1/*
2 * Copyright 2019 Google LLC
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#ifndef SkImageFilters_DEFINED
9#define SkImageFilters_DEFINED
10
11#include "include/core/SkBlendMode.h"
12#include "include/core/SkColor.h"
13#include "include/core/SkFilterQuality.h"
14#include "include/core/SkImage.h"
15#include "include/core/SkImageFilter.h"
16#include "include/core/SkPicture.h"
17#include "include/core/SkRect.h"
18#include "include/core/SkTileMode.h"
19
20class SkColorFilter;
21class SkPaint;
22class SkRegion;
23
24// A set of factory functions providing useful SkImageFilter effects. For image filters that take an
25// input filter, providing nullptr means it will automatically use the dynamic source image. This
26// source depends on how the filter is applied, but is either the contents of a saved layer when
27// drawing with SkCanvas, or an explicit SkImage if using SkImage::makeWithFilter.
28class SK_API SkImageFilters {
29public:
30 /**
31 * Create a filter that updates the alpha of the image based on 'region'. Pixels inside the
32 * region are made more opaque and pixels outside are made more transparent.
33 *
34 * Specifically, if a pixel is inside the region, its alpha will be set to
35 * max(innerMin, pixel's alpha). If a pixel is outside the region, its alpha will be updated to
36 * min(outerMax, pixel's alpha).
37 * @param region The geometric region controlling the inner and outer alpha thresholds.
38 * @param innerMin The minimum alpha value for pixels inside 'region'.
39 * @param outerMax The maximum alpha value for pixels outside of 'region'.
40 * @param input The input filter, or uses the source bitmap if this is null.
41 * @param cropRect Optional rectangle that crops the input and output.
42 */
43 static sk_sp<SkImageFilter> AlphaThreshold(const SkRegion& region, SkScalar innerMin,
44 SkScalar outerMax, sk_sp<SkImageFilter> input,
45 const SkIRect* cropRect = nullptr);
46
47 /**
48 * Create a filter that implements a custom blend mode. Each output pixel is the result of
49 * combining the corresponding background and foreground pixels using the 4 coefficients:
50 * k1 * foreground * background + k2 * foreground + k3 * background + k4
51 * @param k1, k2, k3, k4 The four coefficients used to combine the foreground and background.
52 * @param enforcePMColor If true, the RGB channels will be clamped to the calculated alpha.
53 * @param background The background content, using the source bitmap when this is null.
54 * @param foreground The foreground content, using the source bitmap when this is null.
55 * @param cropRect Optional rectangle that crops the inputs and output.
56 */
57 static sk_sp<SkImageFilter> Arithmetic(SkScalar k1, SkScalar k2, SkScalar k3, SkScalar k4,
58 bool enforcePMColor, sk_sp<SkImageFilter> background,
59 sk_sp<SkImageFilter> foreground,
60 const SkIRect* cropRect = nullptr);
61
62 /**
63 * Create a filter that blurs its input by the separate X and Y sigmas. The provided tile mode
64 * is used when the blur kernel goes outside the input image.
65 * @param sigmaX The Gaussian sigma value for blurring along the X axis.
66 * @param sigmaY The Gaussian sigma value for blurring along the Y axis.
67 * @param tileMode The tile mode applied at edges .
68 * TODO (michaelludwig) - kMirror is not supported yet
69 * @param input The input filter that is blurred, uses source bitmap if this is null.
70 * @param cropRect Optional rectangle that crops the input and output.
71 */
72 static sk_sp<SkImageFilter> Blur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode,
73 sk_sp<SkImageFilter> input, const SkIRect* cropRect = nullptr);
74 // As above, but defaults to the decal tile mode.
75 static sk_sp<SkImageFilter> Blur(SkScalar sigmaX, SkScalar sigmaY, sk_sp<SkImageFilter> input,
76 const SkIRect* cropRect = nullptr) {
77 return Blur(sigmaX, sigmaY, SkTileMode::kDecal, std::move(input), cropRect);
78 }
79
80 /**
81 * Create a filter that applies the color filter to the input filter results.
82 * @param cf The color filter that transforms the input image.
83 * @param input The input filter, or uses the source bitmap if this is null.
84 * @param cropRect Optional rectangle that crops the input and output.
85 */
86 static sk_sp<SkImageFilter> ColorFilter(sk_sp<SkColorFilter> cf, sk_sp<SkImageFilter> input,
87 const SkIRect* cropRect = nullptr);
88
89 /**
90 * Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are
91 * treated as the source bitmap passed to 'outer', i.e. result = outer(inner(source)).
92 * @param outer The outer filter that evaluates the results of inner.
93 * @param inner The inner filter that produces the input to outer.
94 */
95 static sk_sp<SkImageFilter> Compose(sk_sp<SkImageFilter> outer, sk_sp<SkImageFilter> inner);
96
97 /**
98 * Create a filter that moves each pixel in its color input based on an (x,y) vector encoded
99 * in its displacement input filter. Two color components of the displacement image are
100 * mapped into a vector as scale * (color[xChannel], color[yChannel]), where the channel
101 * selectors are one of R, G, B, or A.
102 * @param xChannelSelector RGBA channel that encodes the x displacement per pixel.
103 * @param yChannelSelector RGBA channel that encodes the y displacement per pixel.
104 * @param scale Scale applied to displacement extracted from image.
105 * @param displacement The filter defining the displacement image, or null to use source.
106 * @param color The filter providing the color pixels to be displaced.
107 * @param cropRect Optional rectangle that crops the color input and output.
108 */
109 static sk_sp<SkImageFilter> DisplacementMap(SkColorChannel xChannelSelector,
110 SkColorChannel yChannelSelector,
111 SkScalar scale, sk_sp<SkImageFilter> displacement,
112 sk_sp<SkImageFilter> color,
113 const SkIRect* cropRect = nullptr);
114
115 /**
116 * Create a filter that draws a drop shadow under the input content. This filter produces an
117 * image that includes the inputs' content.
118 * @param dx The X offset of the shadow.
119 * @param dy The Y offset of the shadow.
120 * @param sigmaX The blur radius for the shadow, along the X axis.
121 * @param sigmaY The blur radius for the shadow, along the Y axis.
122 * @param color The color of the drop shadow.
123 * @param input The input filter, or will use the source bitmap if this is null.
124 * @param cropRect Optional rectangle that crops the input and output.
125 */
126 static sk_sp<SkImageFilter> DropShadow(SkScalar dx, SkScalar dy,
127 SkScalar sigmaX, SkScalar sigmaY,
128 SkColor color, sk_sp<SkImageFilter> input,
129 const SkIRect* cropRect = nullptr);
130 /**
131 * Create a filter that renders a drop shadow, in exactly the same manner as ::DropShadow,
132 * except that the resulting image does not include the input content. This allows the shadow
133 * and input to be composed by a filter DAG in a more flexible manner.
134 * @param dx The X offset of the shadow.
135 * @param dy The Y offset of the shadow.
136 * @param sigmaX The blur radius for the shadow, along the X axis.
137 * @param sigmaY The blur radius for the shadow, along the Y axis.
138 * @param color The color of the drop shadow.
139 * @param input The input filter, or will use the source bitmap if this is null.
140 * @param cropRect Optional rectangle that crops the input and output.
141 */
142 static sk_sp<SkImageFilter> DropShadowOnly(SkScalar dx, SkScalar dy,
143 SkScalar sigmaX, SkScalar sigmaY,
144 SkColor color, sk_sp<SkImageFilter> input,
145 const SkIRect* cropRect = nullptr);
146
147 /**
148 * Create a filter that draws the 'srcRect' portion of image into 'dstRect' using the given
149 * filter quality. Similar to SkCanvas::drawImageRect. Returns null if 'image' is null.
150 * @param image The image that is output by the filter, subset by 'srcRect'.
151 * @param srcRect The source pixels sampled into 'dstRect'
152 * @param dstRect The local rectangle to draw the image into.
153 * @param filterQuality The filter quality that is used when sampling the image.
154 */
155 static sk_sp<SkImageFilter> Image(sk_sp<SkImage> image, const SkRect& srcRect,
156 const SkRect& dstRect, SkFilterQuality filterQuality);
157 /**
158 * Create a filter that produces the image contents.
159 * @param image The image that is output by the filter.
160 */
161 static sk_sp<SkImageFilter> Image(sk_sp<SkImage> image) {
162 // Defaults to kHigh_SkFilterQuality because the dstRect of the image filter will be mapped
163 // by the layer matrix set during filtering. If that has a scale factor, then the image
164 // will not be drawn at a 1-to-1 pixel scale, even that is what this appears to create here.
165 SkRect r = image ? SkRect::MakeWH(image->width(), image->height()) : SkRect::MakeEmpty();
166 return Image(std::move(image), r, r, kHigh_SkFilterQuality);
167 }
168
169 /**
170 * Create a filter that mimics a zoom/magnifying lens effect.
171 * @param srcRect
172 * @param inset
173 * @param input The input filter that is magnified, if null the source bitmap is used.
174 * @param cropRect Optional rectangle that crops the input and output.
175 */
176 static sk_sp<SkImageFilter> Magnifier(const SkRect& srcRect, SkScalar inset,
177 sk_sp<SkImageFilter> input,
178 const SkIRect* cropRect = nullptr);
179
180 /**
181 * Create a filter that applies an NxM image processing kernel to the input image. This can be
182 * used to produce effects such as sharpening, blurring, edge detection, etc.
183 * @param kernelSize The kernel size in pixels, in each dimension (N by M).
184 * @param kernel The image processing kernel. Must contain N * M elements, in row order.
185 * @param gain A scale factor applied to each pixel after convolution. This can be
186 * used to normalize the kernel, if it does not already sum to 1.
187 * @param bias A bias factor added to each pixel after convolution.
188 * @param kernelOffset An offset applied to each pixel coordinate before convolution.
189 * This can be used to center the kernel over the image
190 * (e.g., a 3x3 kernel should have an offset of {1, 1}).
191 * @param tileMode How accesses outside the image are treated.
192 * TODO (michaelludwig) - kMirror is not supported yet
193 * @param convolveAlpha If true, all channels are convolved. If false, only the RGB channels
194 * are convolved, and alpha is copied from the source image.
195 * @param input The input image filter, if null the source bitmap is used instead.
196 * @param cropRect Optional rectangle to which the output processing will be limited.
197 */
198 static sk_sp<SkImageFilter> MatrixConvolution(const SkISize& kernelSize,
199 const SkScalar kernel[], SkScalar gain,
200 SkScalar bias, const SkIPoint& kernelOffset,
201 SkTileMode tileMode, bool convolveAlpha,
202 sk_sp<SkImageFilter> input,
203 const SkIRect* cropRect = nullptr);
204
205 /**
206 * Create a filter that transforms the input image by 'matrix'. This matrix transforms the
207 * local space, which means it effectively happens prior to any transformation coming from the
208 * SkCanvas initiating the filtering.
209 * @param matrix The matrix to apply to the original content.
210 * @param filterQuality The filter quality to use when sampling the input image.
211 * @param input The image filter to transform, or null to use the source image.
212 */
213 static sk_sp<SkImageFilter> MatrixTransform(const SkMatrix& matrix,
214 SkFilterQuality filterQuality,
215 sk_sp<SkImageFilter> input);
216
217 /**
218 * Create a filter that merges the 'count' filters together by drawing their results in order
219 * with src-over blending.
220 * @param filters The input filter array to merge, which must have 'count' elements. Any null
221 * filter pointers will use the source bitmap instead.
222 * @param count The number of input filters to be merged.
223 * @param cropRect Optional rectangle that crops all input filters and the output.
224 */
225 static sk_sp<SkImageFilter> Merge(sk_sp<SkImageFilter>* const filters, int count,
226 const SkIRect* cropRect = nullptr);
227 /**
228 * Create a filter that merges the results of the two filters together with src-over blending.
229 * @param first The first input filter, or the source bitmap if this is null.
230 * @param second The second input filter, or the source bitmap if this null.
231 * @param cropRect Optional rectangle that crops the inputs and output.
232 */
233 static sk_sp<SkImageFilter> Merge(sk_sp<SkImageFilter> first, sk_sp<SkImageFilter> second,
234 const SkIRect* cropRect = nullptr) {
235 sk_sp<SkImageFilter> array[] = { std::move(first), std::move(second) };
236 return Merge(array, 2, cropRect);
237 }
238
239 /**
240 * Create a filter that offsets the input filter by the given vector.
241 * @param dx The x offset in local space that the image is shifted.
242 * @param dy The y offset in local space that the image is shifted.
243 * @param input The input that will be moved, if null the source bitmap is used instead.
244 * @param cropRect Optional rectangle to crop the input and output.
245 */
246 static sk_sp<SkImageFilter> Offset(SkScalar dx, SkScalar dy, sk_sp<SkImageFilter> input,
247 const SkIRect* cropRect = nullptr);
248
249 /**
250 * Create a filter that fills the output with the given paint.
251 * @param paint The paint to fill
252 * @param cropRect Optional rectangle that will be filled. If null, the source bitmap's bounds
253 * are filled even though the source bitmap itself is not used.
254 */
255 static sk_sp<SkImageFilter> Paint(const SkPaint& paint, const SkIRect* cropRect = nullptr);
256
257 /**
258 * Create a filter that produces the SkPicture as its output, drawn into targetRect. Note that
259 * the targetRect is not the same as the SkIRect cropRect that many filters accept. Returns
260 * null if 'pic' is null.
261 * @param pic The picture that is drawn for the filter output.
262 * @param targetRect The drawing region for the picture.
263 */
264 static sk_sp<SkImageFilter> Picture(sk_sp<SkPicture> pic, const SkRect& targetRect);
265 // As above, but uses SkPicture::cullRect for the drawing region.
266 static sk_sp<SkImageFilter> Picture(sk_sp<SkPicture> pic) {
267 SkRect target = pic ? pic->cullRect() : SkRect::MakeEmpty();
268 return Picture(std::move(pic), target);
269 }
270
271 /**
272 * Create a tile image filter.
273 * @param src Defines the pixels to tile
274 * @param dst Defines the pixel region that the tiles will be drawn to
275 * @param input The input that will be tiled, if null the source bitmap is used instead.
276 */
277 static sk_sp<SkImageFilter> Tile(const SkRect& src, const SkRect& dst,
278 sk_sp<SkImageFilter> input);
279
280 /**
281 * This filter takes an SkBlendMode and uses it to composite the two filters together.
282 * @param background The Dst pixels used in blending, if null the source bitmap is used.
283 * @param foreground The Src pixels used in blending, if null the source bitmap is used.
284 * @cropRect Optional rectangle to crop input and output.
285 */
286 static sk_sp<SkImageFilter> Xfermode(SkBlendMode, sk_sp<SkImageFilter> background,
287 sk_sp<SkImageFilter> foreground = nullptr,
288 const SkIRect* cropRect = nullptr);
289
290 // Morphology filter effects
291
292 /**
293 * Create a filter that dilates each input pixel's channel values to the max value within the
294 * given radii along the x and y axes.
295 * @param radiusX The distance to dilate along the x axis to either side of each pixel.
296 * @param radiusY The distance to dilate along the y axis to either side of each pixel.
297 * @param input The image filter that is dilated, using source bitmap if this is null.
298 * @param cropRect Optional rectangle that crops the input and output.
299 */
300 static sk_sp<SkImageFilter> Dilate(SkScalar radiusX, SkScalar radiusY,
301 sk_sp<SkImageFilter> input,
302 const SkIRect* cropRect = nullptr);
303
304 /**
305 * Create a filter that erodes each input pixel's channel values to the minimum channel value
306 * within the given radii along the x and y axes.
307 * @param radiusX The distance to erode along the x axis to either side of each pixel.
308 * @param radiusY The distance to erode along the y axis to either side of each pixel.
309 * @param input The image filter that is eroded, using source bitmap if this is null.
310 * @param cropRect Optional rectangle that crops the input and output.
311 */
312 static sk_sp<SkImageFilter> Erode(SkScalar radiusX, SkScalar radiusY,
313 sk_sp<SkImageFilter> input,
314 const SkIRect* cropRect = nullptr);
315
316 // Lighting filter effects
317
318 /**
319 * Create a filter that calculates the diffuse illumination from a distant light source,
320 * interpreting the alpha channel of the input as the height profile of the surface (to
321 * approximate normal vectors).
322 * @param direction The direction to the distance light.
323 * @param lightColor The color of the diffuse light source.
324 * @param surfaceScale Scale factor to transform from alpha values to physical height.
325 * @param kd Diffuse reflectance coefficient.
326 * @param input The input filter that defines surface normals (as alpha), or uses the
327 * source bitmap when null.
328 * @param cropRect Optional rectangle that crops the input and output.
329 */
330 static sk_sp<SkImageFilter> DistantLitDiffuse(const SkPoint3& direction, SkColor lightColor,
331 SkScalar surfaceScale, SkScalar kd,
332 sk_sp<SkImageFilter> input,
333 const SkIRect* cropRect = nullptr);
334 /**
335 * Create a filter that calculates the diffuse illumination from a point light source, using
336 * alpha channel of the input as the height profile of the surface (to approximate normal
337 * vectors).
338 * @param location The location of the point light.
339 * @param lightColor The color of the diffuse light source.
340 * @param surfaceScale Scale factor to transform from alpha values to physical height.
341 * @param kd Diffuse reflectance coefficient.
342 * @param input The input filter that defines surface normals (as alpha), or uses the
343 * source bitmap when null.
344 * @param cropRect Optional rectangle that crops the input and output.
345 */
346 static sk_sp<SkImageFilter> PointLitDiffuse(const SkPoint3& location, SkColor lightColor,
347 SkScalar surfaceScale, SkScalar kd,
348 sk_sp<SkImageFilter> input,
349 const SkIRect* cropRect = nullptr);
350 /**
351 * Create a filter that calculates the diffuse illumination from a spot light source, using
352 * alpha channel of the input as the height profile of the surface (to approximate normal
353 * vectors). The spot light is restricted to be within 'cutoffAngle' of the vector between
354 * the location and target.
355 * @param location The location of the spot light.
356 * @param target The location that the spot light is point towards
357 * @param falloffExponent Exponential falloff parameter for illumination outside of cutoffAngle
358 * @param cutoffAngle Maximum angle from lighting direction that receives full light
359 * @param lightColor The color of the diffuse light source.
360 * @param surfaceScale Scale factor to transform from alpha values to physical height.
361 * @param kd Diffuse reflectance coefficient.
362 * @param input The input filter that defines surface normals (as alpha), or uses the
363 * source bitmap when null.
364 * @param cropRect Optional rectangle that crops the input and output.
365 */
366 static sk_sp<SkImageFilter> SpotLitDiffuse(const SkPoint3& location, const SkPoint3& target,
367 SkScalar falloffExponent, SkScalar cutoffAngle,
368 SkColor lightColor, SkScalar surfaceScale,
369 SkScalar kd, sk_sp<SkImageFilter> input,
370 const SkIRect* cropRect = nullptr);
371
372 /**
373 * Create a filter that calculates the specular illumination from a distant light source,
374 * interpreting the alpha channel of the input as the height profile of the surface (to
375 * approximate normal vectors).
376 * @param direction The direction to the distance light.
377 * @param lightColor The color of the specular light source.
378 * @param surfaceScale Scale factor to transform from alpha values to physical height.
379 * @param ks Specular reflectance coefficient.
380 * @param shininess The specular exponent determining how shiny the surface is.
381 * @param input The input filter that defines surface normals (as alpha), or uses the
382 * source bitmap when null.
383 * @param cropRect Optional rectangle that crops the input and output.
384 */
385 static sk_sp<SkImageFilter> DistantLitSpecular(const SkPoint3& direction, SkColor lightColor,
386 SkScalar surfaceScale, SkScalar ks,
387 SkScalar shininess, sk_sp<SkImageFilter> input,
388 const SkIRect* cropRect = nullptr);
389 /**
390 * Create a filter that calculates the specular illumination from a point light source, using
391 * alpha channel of the input as the height profile of the surface (to approximate normal
392 * vectors).
393 * @param location The location of the point light.
394 * @param lightColor The color of the specular light source.
395 * @param surfaceScale Scale factor to transform from alpha values to physical height.
396 * @param ks Specular reflectance coefficient.
397 * @param shininess The specular exponent determining how shiny the surface is.
398 * @param input The input filter that defines surface normals (as alpha), or uses the
399 * source bitmap when null.
400 * @param cropRect Optional rectangle that crops the input and output.
401 */
402 static sk_sp<SkImageFilter> PointLitSpecular(const SkPoint3& location, SkColor lightColor,
403 SkScalar surfaceScale, SkScalar ks,
404 SkScalar shininess, sk_sp<SkImageFilter> input,
405 const SkIRect* cropRect = nullptr);
406 /**
407 * Create a filter that calculates the specular illumination from a spot light source, using
408 * alpha channel of the input as the height profile of the surface (to approximate normal
409 * vectors). The spot light is restricted to be within 'cutoffAngle' of the vector between
410 * the location and target.
411 * @param location The location of the spot light.
412 * @param target The location that the spot light is point towards
413 * @param falloffExponent Exponential falloff parameter for illumination outside of cutoffAngle
414 * @param cutoffAngle Maximum angle from lighting direction that receives full light
415 * @param lightColor The color of the specular light source.
416 * @param surfaceScale Scale factor to transform from alpha values to physical height.
417 * @param ks Specular reflectance coefficient.
418 * @param shininess The specular exponent determining how shiny the surface is.
419 * @param input The input filter that defines surface normals (as alpha), or uses the
420 * source bitmap when null.
421 * @param cropRect Optional rectangle that crops the input and output.
422 */
423 static sk_sp<SkImageFilter> SpotLitSpecular(const SkPoint3& location, const SkPoint3& target,
424 SkScalar falloffExponent, SkScalar cutoffAngle,
425 SkColor lightColor, SkScalar surfaceScale,
426 SkScalar ks, SkScalar shininess,
427 sk_sp<SkImageFilter> input,
428 const SkIRect* cropRect = nullptr);
429
430 static void RegisterFlattenables();
431
432private:
433 SkImageFilters() = delete;
434};
435
436#endif // SkImageFilters_DEFINED
437