pub enum ImageFilter {
None,
Blur {
sigma_x: f32,
sigma_y: f32,
},
Matrix {
transform: Transform2D,
},
Dilate {
radius_x: f32,
radius_y: f32,
},
Erode {
radius_x: f32,
radius_y: f32,
},
Color(ColorFilter),
Runtime {
program: u32,
uniforms: Vec<f32>,
},
Compose {
outer: Box<ImageFilter>,
inner: Box<ImageFilter>,
},
}Expand description
A function applied to what a paint drew, rather than to the color it computed.
The distinction from a color filter is what the input is. A color filter sees one color at a time and cannot know its neighbors; this sees the picture, which is what a blur needs.
The distinction from Paint::mask_blur is what is blurred. A mask blur
blurs coverage and then fills, which is only the same picture as blurring
the result when the fill does not vary – so it takes a solid color and
refuses anything else. This blurs the result, which is defined for every
paint and is what dart:ui means by an image filter. For a solid color the
two agree, and there is a test that says so.
Variants§
None
Blur
Blur what was drawn, by a standard deviation per axis in device pixels.
Two, because dart:ui’s ImageFilter.blur takes sigmaX and
sigmaY separately and upstream’s MakeBlur passes both through. A
blur is two separable passes here already, one along each axis, so the
second deviation costs nothing but the field: each pass uses its own,
and a pass whose deviation is zero is skipped rather than run as an
identity that would resample for no reason.
Self::blur is the isotropic case, which is nearly every use.
Matrix
Move what was drawn, in device pixels, by resampling it.
Not the same as drawing under the transform, which is what the canvas’s
own stack does. This draws at the size it was written and then moves
the finished image, so magnifying gives enlarged pixels where the
transform stack would give the shape redrawn larger. That difference is
the reason dart:ui has both, and a caller wanting the sharp one
already has concat.
Fields
transform: Transform2DDilate
Spread what was drawn, taking the largest sample within these radii in device pixels.
ImageFilter.dilate. On premultiplied color and channel by channel, so
a translucent shape spreads its coverage along with its color.
Erode
Shrink what was drawn, taking the smallest sample within these radii in device pixels.
ImageFilter.erode, and the dual of Self::Dilate: what one does to
a shape the other does to the space around it.
Color(ColorFilter)
Recolor what was drawn, rather than what the paint computed.
dart:ui’s ColorFilter is itself an ImageFilter, and upstream’s
DlImageFilter::MakeColorFilter is the same thing. A paint carries a
color filter of its own, so the obvious question is what this adds, and
the answer is narrower than it first looks: it can be half of a
Self::Compose, and Paint::color_filter cannot. Recoloring a
blurred result, or blurring a recolored one, has no other spelling here.
On a single draw with a solid fill it is the same picture as the paint’s own filter, and a test pins that rather than leaving it to be discovered. A paint’s image filter applies per draw – each draw gets a layer of its own – so there is no arrangement of two draws under one paint for the two to disagree about. Where they would disagree is inside a composition, which is the case this exists for.
Runtime
Run a caller’s fragment program over what was drawn.
dart:ui’s ImageFilter.shader, and upstream’s
DlImageFilter::MakeRuntimeEffect. The program reads its input as a
texture with an identity transform – the same guarantee upstream
re-rasterizes to provide, and one this renderer has by construction: a
filter is a pass whose target is the size of its source, covered by a
quad, so a fragment’s clip position is its texture coordinate. A
program written for this samples exactly as the fixture programs do.
The uniforms are the whole material block, because a program replaces
the shader that would have read it. RUNTIME_FLOATS is the bound and
anything past it is dropped, as it is for a runtime effect used as a
paint.
Compose
Filter with inner, then filter that result with outer.
ImageFilter.compose, and the reason this type is not Copy: a filter
that holds filters cannot be a fixed size without a bound on the depth,
and dart:ui puts no bound on it.
A caller can already nest Canvas::save_layer calls to the same
effect, and did before this existed. What this adds is that the bounds
come out right without being worked out by hand: the outer layer has to
be opened wide enough to hold whatever the inner one grew to, which
means knowing how far each filter in the chain reaches.
Implementations§
Source§impl ImageFilter
impl ImageFilter
Sourcepub fn blur(sigma: f32) -> ImageFilter
pub fn blur(sigma: f32) -> ImageFilter
A blur of the same deviation along both axes, which is nearly every use.
Sourcepub fn blur_xy(sigma_x: f32, sigma_y: f32) -> ImageFilter
pub fn blur_xy(sigma_x: f32, sigma_y: f32) -> ImageFilter
A blur with a deviation per axis, as dart:ui’s ImageFilter.blur
states one.
Sourcepub fn is_identity(&self) -> bool
pub fn is_identity(&self) -> bool
Whether this would change anything.
Sourcepub fn compose(outer: ImageFilter, inner: ImageFilter) -> ImageFilter
pub fn compose(outer: ImageFilter, inner: ImageFilter) -> ImageFilter
Filter with inner first and then with outer.
The order dart:ui states, which is the order the names suggest once
you picture them nested: the inner filter is the one closer to what was
drawn. A composition where either half does nothing is the other half,
since the layer it would have taken is a copy of an image.
Trait Implementations§
Source§impl Clone for ImageFilter
impl Clone for ImageFilter
Source§fn clone(&self) -> ImageFilter
fn clone(&self) -> ImageFilter
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more