mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Create ImageFilter.dilate/ImageFilter.erode (flutter/engine#32334)
This commit is contained in:
parent
a0b860283e
commit
a6ca392650
@ -193,6 +193,20 @@ void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
|
||||
new (pod) DlBlurImageFilter(blur_filter);
|
||||
break;
|
||||
}
|
||||
case DlImageFilterType::kDilate: {
|
||||
const DlDilateImageFilter* dilate_filter = filter->asDilate();
|
||||
FML_DCHECK(dilate_filter);
|
||||
void* pod = Push<SetPodImageFilterOp>(dilate_filter->size(), 0);
|
||||
new (pod) DlDilateImageFilter(dilate_filter);
|
||||
break;
|
||||
}
|
||||
case DlImageFilterType::kErode: {
|
||||
const DlErodeImageFilter* erode_filter = filter->asErode();
|
||||
FML_DCHECK(erode_filter);
|
||||
void* pod = Push<SetPodImageFilterOp>(erode_filter->size(), 0);
|
||||
new (pod) DlErodeImageFilter(erode_filter);
|
||||
break;
|
||||
}
|
||||
case DlImageFilterType::kMatrix: {
|
||||
const DlMatrixImageFilter* matrix_filter = filter->asMatrix();
|
||||
FML_DCHECK(matrix_filter);
|
||||
|
||||
@ -1121,6 +1121,65 @@ class CanvasCompareTester {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Being able to see a dilate requires some non-default attributes,
|
||||
// like a non-trivial stroke width and a shader rather than a color
|
||||
// (for drawPaint) so we create a new environment for these tests.
|
||||
RenderEnvironment dilate_env = RenderEnvironment::MakeN32();
|
||||
CvSetup cv_dilate_setup = [=](SkCanvas*, SkPaint& p) {
|
||||
p.setShader(testImageColorSource.skia_object());
|
||||
p.setStrokeWidth(5.0);
|
||||
};
|
||||
DlRenderer dl_dilate_setup = [=](DisplayListBuilder& b) {
|
||||
b.setColorSource(&testImageColorSource);
|
||||
b.setStrokeWidth(5.0);
|
||||
};
|
||||
dilate_env.init_ref(cv_dilate_setup, testP.cv_renderer(),
|
||||
dl_dilate_setup);
|
||||
DlDilateImageFilter filter_5(5.0, 5.0);
|
||||
RenderWith(testP, dilate_env, tolerance,
|
||||
CaseParameters(
|
||||
"ImageFilter == Dilate 5",
|
||||
[=](SkCanvas* cv, SkPaint& p) {
|
||||
cv_dilate_setup(cv, p);
|
||||
p.setImageFilter(filter_5.skia_object());
|
||||
},
|
||||
[=](DisplayListBuilder& b) {
|
||||
dl_dilate_setup(b);
|
||||
b.setImageFilter(&filter_5);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
// Being able to see an erode requires some non-default attributes,
|
||||
// like a non-trivial stroke width and a shader rather than a color
|
||||
// (for drawPaint) so we create a new environment for these tests.
|
||||
RenderEnvironment erode_env = RenderEnvironment::MakeN32();
|
||||
CvSetup cv_erode_setup = [=](SkCanvas*, SkPaint& p) {
|
||||
p.setShader(testImageColorSource.skia_object());
|
||||
p.setStrokeWidth(6.0);
|
||||
};
|
||||
DlRenderer dl_erode_setup = [=](DisplayListBuilder& b) {
|
||||
b.setColorSource(&testImageColorSource);
|
||||
b.setStrokeWidth(6.0);
|
||||
};
|
||||
erode_env.init_ref(cv_erode_setup, testP.cv_renderer(), dl_erode_setup);
|
||||
// do not erode too much, because some tests assert there are enough
|
||||
// pixels that are changed.
|
||||
DlErodeImageFilter filter_1(1.0, 1.0);
|
||||
RenderWith(testP, erode_env, tolerance,
|
||||
CaseParameters(
|
||||
"ImageFilter == Erode 1",
|
||||
[=](SkCanvas* cv, SkPaint& p) {
|
||||
cv_erode_setup(cv, p);
|
||||
p.setImageFilter(filter_1.skia_object());
|
||||
},
|
||||
[=](DisplayListBuilder& b) {
|
||||
dl_erode_setup(b);
|
||||
b.setImageFilter(&filter_1);
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
// clang-format off
|
||||
constexpr float rotate_color_matrix[20] = {
|
||||
|
||||
@ -28,6 +28,8 @@ namespace flutter {
|
||||
// provided as a fallback.
|
||||
enum class DlImageFilterType {
|
||||
kBlur,
|
||||
kDilate,
|
||||
kErode,
|
||||
kMatrix,
|
||||
kComposeFilter,
|
||||
kColorFilter,
|
||||
@ -35,6 +37,8 @@ enum class DlImageFilterType {
|
||||
};
|
||||
|
||||
class DlBlurImageFilter;
|
||||
class DlDilateImageFilter;
|
||||
class DlErodeImageFilter;
|
||||
class DlMatrixImageFilter;
|
||||
class DlComposeImageFilter;
|
||||
class DlColorFilterImageFilter;
|
||||
@ -64,6 +68,14 @@ class DlImageFilter
|
||||
// type of ImageFilter, otherwise return nullptr.
|
||||
virtual const DlBlurImageFilter* asBlur() const { return nullptr; }
|
||||
|
||||
// Return a DlDilateImageFilter pointer to this object iff it is a Dilate
|
||||
// type of ImageFilter, otherwise return nullptr.
|
||||
virtual const DlDilateImageFilter* asDilate() const { return nullptr; }
|
||||
|
||||
// Return a DlErodeImageFilter pointer to this object iff it is an Erode
|
||||
// type of ImageFilter, otherwise return nullptr.
|
||||
virtual const DlErodeImageFilter* asErode() const { return nullptr; }
|
||||
|
||||
// Return a DlMatrixImageFilter pointer to this object iff it is a Matrix
|
||||
// type of ImageFilter, otherwise return nullptr.
|
||||
virtual const DlMatrixImageFilter* asMatrix() const { return nullptr; }
|
||||
@ -140,7 +152,7 @@ class DlBlurImageFilter final : public DlImageFilter {
|
||||
SkIRect* map_device_bounds(const SkIRect& input_bounds,
|
||||
const SkMatrix& ctm,
|
||||
SkIRect& output_bounds) const override {
|
||||
SkVector device_sigma = ctm.mapVector(sigma_x_, sigma_y_);
|
||||
SkVector device_sigma = ctm.mapVector(sigma_x_ * 3, sigma_y_ * 3);
|
||||
if (!SkScalarIsFinite(device_sigma.fX)) {
|
||||
device_sigma.fX = 0;
|
||||
}
|
||||
@ -174,6 +186,126 @@ class DlBlurImageFilter final : public DlImageFilter {
|
||||
DlTileMode tile_mode_;
|
||||
};
|
||||
|
||||
class DlDilateImageFilter final : public DlImageFilter {
|
||||
public:
|
||||
DlDilateImageFilter(SkScalar radius_x, SkScalar radius_y)
|
||||
: radius_x_(radius_x), radius_y_(radius_y) {}
|
||||
explicit DlDilateImageFilter(const DlDilateImageFilter* filter)
|
||||
: DlDilateImageFilter(filter->radius_x_, filter->radius_y_) {}
|
||||
explicit DlDilateImageFilter(const DlDilateImageFilter& filter)
|
||||
: DlDilateImageFilter(&filter) {}
|
||||
|
||||
std::shared_ptr<DlImageFilter> shared() const override {
|
||||
return std::make_shared<DlDilateImageFilter>(this);
|
||||
}
|
||||
|
||||
DlImageFilterType type() const override { return DlImageFilterType::kDilate; }
|
||||
size_t size() const override { return sizeof(*this); }
|
||||
|
||||
const DlDilateImageFilter* asDilate() const override { return this; }
|
||||
|
||||
bool modifies_transparent_black() const override { return false; }
|
||||
|
||||
SkRect* map_local_bounds(const SkRect& input_bounds,
|
||||
SkRect& output_bounds) const override {
|
||||
output_bounds = input_bounds.makeOutset(radius_x_, radius_y_);
|
||||
return &output_bounds;
|
||||
}
|
||||
|
||||
SkIRect* map_device_bounds(const SkIRect& input_bounds,
|
||||
const SkMatrix& ctm,
|
||||
SkIRect& output_bounds) const override {
|
||||
SkVector device_radius = ctm.mapVector(radius_x_, radius_y_);
|
||||
if (!SkScalarIsFinite(device_radius.fX)) {
|
||||
device_radius.fX = 0;
|
||||
}
|
||||
if (!SkScalarIsFinite(device_radius.fY)) {
|
||||
device_radius.fY = 0;
|
||||
}
|
||||
output_bounds = input_bounds.makeOutset(ceil(abs(device_radius.fX)),
|
||||
ceil(abs(device_radius.fY)));
|
||||
return &output_bounds;
|
||||
}
|
||||
|
||||
SkScalar radius_x() const { return radius_x_; }
|
||||
SkScalar radius_y() const { return radius_y_; }
|
||||
|
||||
sk_sp<SkImageFilter> skia_object() const override {
|
||||
return SkImageFilters::Dilate(radius_x_, radius_y_, nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool equals_(const DlImageFilter& other) const override {
|
||||
FML_DCHECK(other.type() == DlImageFilterType::kDilate);
|
||||
auto that = static_cast<const DlDilateImageFilter*>(&other);
|
||||
return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_);
|
||||
}
|
||||
|
||||
private:
|
||||
SkScalar radius_x_;
|
||||
SkScalar radius_y_;
|
||||
};
|
||||
|
||||
class DlErodeImageFilter final : public DlImageFilter {
|
||||
public:
|
||||
DlErodeImageFilter(SkScalar radius_x, SkScalar radius_y)
|
||||
: radius_x_(radius_x), radius_y_(radius_y) {}
|
||||
explicit DlErodeImageFilter(const DlErodeImageFilter* filter)
|
||||
: DlErodeImageFilter(filter->radius_x_, filter->radius_y_) {}
|
||||
explicit DlErodeImageFilter(const DlErodeImageFilter& filter)
|
||||
: DlErodeImageFilter(&filter) {}
|
||||
|
||||
std::shared_ptr<DlImageFilter> shared() const override {
|
||||
return std::make_shared<DlErodeImageFilter>(this);
|
||||
}
|
||||
|
||||
DlImageFilterType type() const override { return DlImageFilterType::kErode; }
|
||||
size_t size() const override { return sizeof(*this); }
|
||||
|
||||
const DlErodeImageFilter* asErode() const override { return this; }
|
||||
|
||||
bool modifies_transparent_black() const override { return false; }
|
||||
|
||||
SkRect* map_local_bounds(const SkRect& input_bounds,
|
||||
SkRect& output_bounds) const override {
|
||||
output_bounds = input_bounds.makeOutset(radius_x_, radius_y_);
|
||||
return &output_bounds;
|
||||
}
|
||||
|
||||
SkIRect* map_device_bounds(const SkIRect& input_bounds,
|
||||
const SkMatrix& ctm,
|
||||
SkIRect& output_bounds) const override {
|
||||
SkVector device_radius = ctm.mapVector(radius_x_, radius_y_);
|
||||
if (!SkScalarIsFinite(device_radius.fX)) {
|
||||
device_radius.fX = 0;
|
||||
}
|
||||
if (!SkScalarIsFinite(device_radius.fY)) {
|
||||
device_radius.fY = 0;
|
||||
}
|
||||
output_bounds = input_bounds.makeOutset(ceil(abs(device_radius.fX)),
|
||||
ceil(abs(device_radius.fY)));
|
||||
return &output_bounds;
|
||||
}
|
||||
|
||||
SkScalar radius_x() const { return radius_x_; }
|
||||
SkScalar radius_y() const { return radius_y_; }
|
||||
|
||||
sk_sp<SkImageFilter> skia_object() const override {
|
||||
return SkImageFilters::Erode(radius_x_, radius_y_, nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool equals_(const DlImageFilter& other) const override {
|
||||
FML_DCHECK(other.type() == DlImageFilterType::kErode);
|
||||
auto that = static_cast<const DlErodeImageFilter*>(&other);
|
||||
return (radius_x_ == that->radius_x_ && radius_y_ == that->radius_y_);
|
||||
}
|
||||
|
||||
private:
|
||||
SkScalar radius_x_;
|
||||
SkScalar radius_y_;
|
||||
};
|
||||
|
||||
class DlMatrixImageFilter final : public DlImageFilter {
|
||||
public:
|
||||
DlMatrixImageFilter(const SkMatrix& matrix, const SkSamplingOptions& sampling)
|
||||
|
||||
@ -43,6 +43,40 @@ TEST(DisplayListImageFilter, FromSkiaBlurImageFilter) {
|
||||
|
||||
// We cannot recapture the blur parameters from an SkBlurImageFilter
|
||||
ASSERT_EQ(filter->asBlur(), nullptr);
|
||||
ASSERT_EQ(filter->asDilate(), nullptr);
|
||||
ASSERT_EQ(filter->asErode(), nullptr);
|
||||
ASSERT_EQ(filter->asMatrix(), nullptr);
|
||||
ASSERT_EQ(filter->asCompose(), nullptr);
|
||||
ASSERT_EQ(filter->asColorFilter(), nullptr);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, FromSkiaDilateImageFilter) {
|
||||
sk_sp<SkImageFilter> sk_image_filter =
|
||||
SkImageFilters::Dilate(5.0, 5.0, nullptr);
|
||||
std::shared_ptr<DlImageFilter> filter = DlImageFilter::From(sk_image_filter);
|
||||
|
||||
ASSERT_EQ(filter->type(), DlImageFilterType::kUnknown);
|
||||
|
||||
// We cannot recapture the dilate parameters from an SkDilateImageFilter
|
||||
ASSERT_EQ(filter->asBlur(), nullptr);
|
||||
ASSERT_EQ(filter->asDilate(), nullptr);
|
||||
ASSERT_EQ(filter->asErode(), nullptr);
|
||||
ASSERT_EQ(filter->asMatrix(), nullptr);
|
||||
ASSERT_EQ(filter->asCompose(), nullptr);
|
||||
ASSERT_EQ(filter->asColorFilter(), nullptr);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, FromSkiaErodeImageFilter) {
|
||||
sk_sp<SkImageFilter> sk_image_filter =
|
||||
SkImageFilters::Erode(5.0, 5.0, nullptr);
|
||||
std::shared_ptr<DlImageFilter> filter = DlImageFilter::From(sk_image_filter);
|
||||
|
||||
ASSERT_EQ(filter->type(), DlImageFilterType::kUnknown);
|
||||
|
||||
// We cannot recapture the erode parameters from an SkErodeImageFilter
|
||||
ASSERT_EQ(filter->asBlur(), nullptr);
|
||||
ASSERT_EQ(filter->asDilate(), nullptr);
|
||||
ASSERT_EQ(filter->asErode(), nullptr);
|
||||
ASSERT_EQ(filter->asMatrix(), nullptr);
|
||||
ASSERT_EQ(filter->asCompose(), nullptr);
|
||||
ASSERT_EQ(filter->asColorFilter(), nullptr);
|
||||
@ -57,6 +91,8 @@ TEST(DisplayListImageFilter, FromSkiaMatrixImageFilter) {
|
||||
|
||||
// We cannot recapture the blur parameters from an SkMatrixImageFilter
|
||||
ASSERT_EQ(filter->asBlur(), nullptr);
|
||||
ASSERT_EQ(filter->asDilate(), nullptr);
|
||||
ASSERT_EQ(filter->asErode(), nullptr);
|
||||
ASSERT_EQ(filter->asMatrix(), nullptr);
|
||||
ASSERT_EQ(filter->asCompose(), nullptr);
|
||||
ASSERT_EQ(filter->asColorFilter(), nullptr);
|
||||
@ -75,6 +111,8 @@ TEST(DisplayListImageFilter, FromSkiaComposeImageFilter) {
|
||||
|
||||
// We cannot recapture the blur parameters from an SkComposeImageFilter
|
||||
ASSERT_EQ(filter->asBlur(), nullptr);
|
||||
ASSERT_EQ(filter->asDilate(), nullptr);
|
||||
ASSERT_EQ(filter->asErode(), nullptr);
|
||||
ASSERT_EQ(filter->asMatrix(), nullptr);
|
||||
ASSERT_EQ(filter->asCompose(), nullptr);
|
||||
ASSERT_EQ(filter->asColorFilter(), nullptr);
|
||||
@ -96,6 +134,8 @@ TEST(DisplayListImageFilter, FromSkiaColorFilterImageFilter) {
|
||||
ASSERT_EQ(*filter->asColorFilter()->color_filter(), dl_color_filter);
|
||||
|
||||
ASSERT_EQ(filter->asBlur(), nullptr);
|
||||
ASSERT_EQ(filter->asDilate(), nullptr);
|
||||
ASSERT_EQ(filter->asErode(), nullptr);
|
||||
ASSERT_EQ(filter->asMatrix(), nullptr);
|
||||
ASSERT_EQ(filter->asCompose(), nullptr);
|
||||
ASSERT_NE(filter->asColorFilter(), nullptr);
|
||||
@ -145,6 +185,88 @@ TEST(DisplayListImageFilter, BlurNotEquals) {
|
||||
TestNotEquals(filter1, filter4, "Tile Mode differs");
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, DilateConstructor) {
|
||||
DlDilateImageFilter filter(5.0, 6.0);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, DilateShared) {
|
||||
DlDilateImageFilter filter(5.0, 6.0);
|
||||
|
||||
ASSERT_NE(filter.shared().get(), &filter);
|
||||
ASSERT_EQ(*filter.shared(), filter);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, DilateAsDilate) {
|
||||
DlDilateImageFilter filter(5.0, 6.0);
|
||||
|
||||
ASSERT_NE(filter.asDilate(), nullptr);
|
||||
ASSERT_EQ(filter.asDilate(), &filter);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, DilateContents) {
|
||||
DlDilateImageFilter filter(5.0, 6.0);
|
||||
|
||||
ASSERT_EQ(filter.radius_x(), 5.0);
|
||||
ASSERT_EQ(filter.radius_y(), 6.0);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, DilateEquals) {
|
||||
DlDilateImageFilter filter1(5.0, 6.0);
|
||||
DlDilateImageFilter filter2(5.0, 6.0);
|
||||
|
||||
TestEquals(filter1, filter2);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, DilateNotEquals) {
|
||||
DlDilateImageFilter filter1(5.0, 6.0);
|
||||
DlDilateImageFilter filter2(7.0, 6.0);
|
||||
DlDilateImageFilter filter3(5.0, 8.0);
|
||||
|
||||
TestNotEquals(filter1, filter2, "Radius X differs");
|
||||
TestNotEquals(filter1, filter3, "Radius Y differs");
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, ErodeConstructor) {
|
||||
DlErodeImageFilter filter(5.0, 6.0);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, ErodeShared) {
|
||||
DlErodeImageFilter filter(5.0, 6.0);
|
||||
|
||||
ASSERT_NE(filter.shared().get(), &filter);
|
||||
ASSERT_EQ(*filter.shared(), filter);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, ErodeAsErode) {
|
||||
DlErodeImageFilter filter(5.0, 6.0);
|
||||
|
||||
ASSERT_NE(filter.asErode(), nullptr);
|
||||
ASSERT_EQ(filter.asErode(), &filter);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, ErodeContents) {
|
||||
DlErodeImageFilter filter(5.0, 6.0);
|
||||
|
||||
ASSERT_EQ(filter.radius_x(), 5.0);
|
||||
ASSERT_EQ(filter.radius_y(), 6.0);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, ErodeEquals) {
|
||||
DlErodeImageFilter filter1(5.0, 6.0);
|
||||
DlErodeImageFilter filter2(5.0, 6.0);
|
||||
|
||||
TestEquals(filter1, filter2);
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, ErodeNotEquals) {
|
||||
DlErodeImageFilter filter1(5.0, 6.0);
|
||||
DlErodeImageFilter filter2(7.0, 6.0);
|
||||
DlErodeImageFilter filter3(5.0, 8.0);
|
||||
|
||||
TestNotEquals(filter1, filter2, "Radius X differs");
|
||||
TestNotEquals(filter1, filter3, "Radius Y differs");
|
||||
}
|
||||
|
||||
TEST(DisplayListImageFilter, MatrixConstructor) {
|
||||
DlMatrixImageFilter filter(SkMatrix::MakeAll(2.0, 0.0, 10, //
|
||||
0.5, 3.0, 15, //
|
||||
|
||||
@ -149,6 +149,12 @@ static const DlBlurImageFilter TestBlurImageFilter3(5.0,
|
||||
static const DlBlurImageFilter TestBlurImageFilter4(5.0,
|
||||
5.0,
|
||||
DlTileMode::kDecal);
|
||||
static const DlDilateImageFilter TestDilateImageFilter1(5.0, 5.0);
|
||||
static const DlDilateImageFilter TestDilateImageFilter2(6.0, 5.0);
|
||||
static const DlDilateImageFilter TestDilateImageFilter3(5.0, 6.0);
|
||||
static const DlErodeImageFilter TestErodeImageFilter1(5.0, 5.0);
|
||||
static const DlErodeImageFilter TestErodeImageFilter2(6.0, 5.0);
|
||||
static const DlErodeImageFilter TestErodeImageFilter3(5.0, 6.0);
|
||||
static const DlMatrixImageFilter TestMatrixImageFilter1(SkMatrix::RotateDeg(45),
|
||||
NearestSampling);
|
||||
static const DlMatrixImageFilter TestMatrixImageFilter2(SkMatrix::RotateDeg(85),
|
||||
@ -391,6 +397,12 @@ std::vector<DisplayListInvocationGroup> allGroups = {
|
||||
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestBlurImageFilter2);}},
|
||||
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestBlurImageFilter3);}},
|
||||
{0, 32, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestBlurImageFilter4);}},
|
||||
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestDilateImageFilter1);}},
|
||||
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestDilateImageFilter2);}},
|
||||
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestDilateImageFilter3);}},
|
||||
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestErodeImageFilter1);}},
|
||||
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestErodeImageFilter2);}},
|
||||
{0, 24, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestErodeImageFilter3);}},
|
||||
{0, 80, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestMatrixImageFilter1);}},
|
||||
{0, 80, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestMatrixImageFilter2);}},
|
||||
{0, 80, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(&TestMatrixImageFilter3);}},
|
||||
|
||||
@ -3224,6 +3224,22 @@ abstract class ImageFilter {
|
||||
return _GaussianBlurImageFilter(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode);
|
||||
}
|
||||
|
||||
/// Creates an image filter that dilates each input pixel's channel values
|
||||
/// to the max value within the given radii along the x and y axes.
|
||||
factory ImageFilter.dilate({ double radiusX = 0.0, double radiusY = 0.0 }) {
|
||||
assert(radiusX != null);
|
||||
assert(radiusY != null);
|
||||
return _DilateImageFilter(radiusX: radiusX, radiusY: radiusY);
|
||||
}
|
||||
|
||||
/// Create a filter that erodes each input pixel's channel values
|
||||
/// to the minimum channel value within the given radii along the x and y axes.
|
||||
factory ImageFilter.erode({ double radiusX = 0.0, double radiusY = 0.0 }) {
|
||||
assert(radiusX != null);
|
||||
assert(radiusY != null);
|
||||
return _ErodeImageFilter(radiusX: radiusX, radiusY: radiusY);
|
||||
}
|
||||
|
||||
/// Creates an image filter that applies a matrix transformation.
|
||||
///
|
||||
/// For example, applying a positive scale matrix (see [Matrix4.diagonal3])
|
||||
@ -3327,6 +3343,64 @@ class _GaussianBlurImageFilter implements ImageFilter {
|
||||
int get hashCode => hashValues(sigmaX, sigmaY);
|
||||
}
|
||||
|
||||
class _DilateImageFilter implements ImageFilter {
|
||||
_DilateImageFilter({ required this.radiusX, required this.radiusY });
|
||||
|
||||
final double radiusX;
|
||||
final double radiusY;
|
||||
|
||||
late final _ImageFilter nativeFilter = _ImageFilter.dilate(this);
|
||||
@override
|
||||
_ImageFilter _toNativeImageFilter() => nativeFilter;
|
||||
|
||||
@override
|
||||
String get _shortDescription => 'dilate($radiusX, $radiusY)';
|
||||
|
||||
@override
|
||||
String toString() => 'ImageFilter.dilate($radiusX, $radiusY)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
return other is _DilateImageFilter
|
||||
&& other.radiusX == radiusX
|
||||
&& other.radiusY == radiusY;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(radiusX, radiusY);
|
||||
}
|
||||
|
||||
class _ErodeImageFilter implements ImageFilter {
|
||||
_ErodeImageFilter({ required this.radiusX, required this.radiusY });
|
||||
|
||||
final double radiusX;
|
||||
final double radiusY;
|
||||
|
||||
late final _ImageFilter nativeFilter = _ImageFilter.erode(this);
|
||||
@override
|
||||
_ImageFilter _toNativeImageFilter() => nativeFilter;
|
||||
|
||||
@override
|
||||
String get _shortDescription => 'erode($radiusX, $radiusY)';
|
||||
|
||||
@override
|
||||
String toString() => 'ImageFilter.erode($radiusX, $radiusY)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
return false;
|
||||
return other is _ErodeImageFilter
|
||||
&& other.radiusX == radiusX
|
||||
&& other.radiusY == radiusY;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(radiusX, radiusY);
|
||||
}
|
||||
|
||||
class _ComposeImageFilter implements ImageFilter {
|
||||
_ComposeImageFilter({ required this.innerFilter, required this.outerFilter });
|
||||
|
||||
@ -3374,6 +3448,26 @@ class _ImageFilter extends NativeFieldWrapperClass1 {
|
||||
}
|
||||
void _initBlur(double sigmaX, double sigmaY, int tileMode) native 'ImageFilter_initBlur';
|
||||
|
||||
/// Creates an image filter that dilates each input pixel's channel values
|
||||
/// to the max value within the given radii along the x and y axes.
|
||||
_ImageFilter.dilate(_DilateImageFilter filter)
|
||||
: assert(filter != null),
|
||||
creator = filter { // ignore: prefer_initializing_formals
|
||||
_constructor();
|
||||
_initDilate(filter.radiusX, filter.radiusY);
|
||||
}
|
||||
void _initDilate(double radiusX, double radiusY) native 'ImageFilter_initDilate';
|
||||
|
||||
/// Create a filter that erodes each input pixel's channel values
|
||||
/// to the minimum channel value within the given radii along the x and y axes.
|
||||
_ImageFilter.erode(_ErodeImageFilter filter)
|
||||
: assert(filter != null),
|
||||
creator = filter { // ignore: prefer_initializing_formals
|
||||
_constructor();
|
||||
_initErode(filter.radiusX, filter.radiusY);
|
||||
}
|
||||
void _initErode(double radiusX, double radiusY) native 'ImageFilter_initErode';
|
||||
|
||||
/// Creates an image filter that applies a matrix transformation.
|
||||
///
|
||||
/// For example, applying a positive scale matrix (see [Matrix4.diagonal3])
|
||||
|
||||
@ -22,6 +22,8 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, ImageFilter);
|
||||
|
||||
#define FOR_EACH_BINDING(V) \
|
||||
V(ImageFilter, initBlur) \
|
||||
V(ImageFilter, initDilate) \
|
||||
V(ImageFilter, initErode) \
|
||||
V(ImageFilter, initMatrix) \
|
||||
V(ImageFilter, initColorFilter) \
|
||||
V(ImageFilter, initComposeFilter)
|
||||
@ -74,6 +76,14 @@ void ImageFilter::initBlur(double sigma_x,
|
||||
std::make_shared<DlBlurImageFilter>(sigma_x, sigma_y, ToDl(tile_mode));
|
||||
}
|
||||
|
||||
void ImageFilter::initDilate(double radius_x, double radius_y) {
|
||||
filter_ = std::make_shared<DlDilateImageFilter>(radius_x, radius_y);
|
||||
}
|
||||
|
||||
void ImageFilter::initErode(double radius_x, double radius_y) {
|
||||
filter_ = std::make_shared<DlErodeImageFilter>(radius_x, radius_y);
|
||||
}
|
||||
|
||||
void ImageFilter::initMatrix(const tonic::Float64List& matrix4,
|
||||
int filterQualityIndex) {
|
||||
auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex);
|
||||
|
||||
@ -30,6 +30,8 @@ class ImageFilter : public RefCountedDartWrappable<ImageFilter> {
|
||||
static SkFilterMode FilterModeFromIndex(int index);
|
||||
|
||||
void initBlur(double sigma_x, double sigma_y, SkTileMode tile_mode);
|
||||
void initDilate(double radius_x, double radius_y);
|
||||
void initErode(double radius_x, double radius_y);
|
||||
void initMatrix(const tonic::Float64List& matrix4, int filter_quality_index);
|
||||
void initColorFilter(ColorFilter* colorFilter);
|
||||
void initComposeFilter(ImageFilter* outer, ImageFilter* inner);
|
||||
|
||||
@ -405,6 +405,20 @@ class ImageFilter {
|
||||
return engine.EngineImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode);
|
||||
}
|
||||
|
||||
// ignore: avoid_unused_constructor_parameters
|
||||
factory ImageFilter.dilate({ double radiusX = 0.0, double radiusY = 0.0 }) {
|
||||
// TODO(fzyzcjy): implement dilate. https://github.com/flutter/flutter/issues/101085
|
||||
throw UnimplementedError(
|
||||
'ImageFilter.dilate not implemented for web platform.');
|
||||
}
|
||||
|
||||
// ignore: avoid_unused_constructor_parameters
|
||||
factory ImageFilter.erode({ double radiusX = 0.0, double radiusY = 0.0 }) {
|
||||
// TODO(fzyzcjy): implement erode. https://github.com/flutter/flutter/issues/101085
|
||||
throw UnimplementedError(
|
||||
'ImageFilter.erode not implemented for web platform.');
|
||||
}
|
||||
|
||||
factory ImageFilter.matrix(Float64List matrix4, {FilterQuality filterQuality = FilterQuality.low}) {
|
||||
if (matrix4.length != 16)
|
||||
throw ArgumentError('"matrix4" must have 16 entries.');
|
||||
|
||||
@ -394,6 +394,18 @@ void main() {
|
||||
oldLayer: oldLayer as ImageFilterEngineLayer?,
|
||||
);
|
||||
});
|
||||
testNoSharing((SceneBuilder builder, EngineLayer? oldLayer) {
|
||||
return builder.pushImageFilter(
|
||||
ImageFilter.dilate(radiusX: 10.0, radiusY: 10.0),
|
||||
oldLayer: oldLayer as ImageFilterEngineLayer?,
|
||||
);
|
||||
});
|
||||
testNoSharing((SceneBuilder builder, EngineLayer? oldLayer) {
|
||||
return builder.pushImageFilter(
|
||||
ImageFilter.erode(radiusX: 10.0, radiusY: 10.0),
|
||||
oldLayer: oldLayer as ImageFilterEngineLayer?,
|
||||
);
|
||||
});
|
||||
testNoSharing((SceneBuilder builder, EngineLayer? oldLayer) {
|
||||
return builder.pushImageFilter(
|
||||
ImageFilter.matrix(Float64List.fromList(<double>[
|
||||
|
||||
@ -74,6 +74,12 @@ void main() {
|
||||
ImageFilter makeBlur(double sigmaX, double sigmaY, [TileMode tileMode = TileMode.clamp]) =>
|
||||
ImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode);
|
||||
|
||||
ImageFilter makeDilate(double radiusX, double radiusY) =>
|
||||
ImageFilter.dilate(radiusX: radiusX, radiusY: radiusY);
|
||||
|
||||
ImageFilter makeErode(double radiusX, double radiusY) =>
|
||||
ImageFilter.erode(radiusX: radiusX, radiusY: radiusY);
|
||||
|
||||
ImageFilter makeScale(double scX, double scY,
|
||||
[double trX = 0.0, double trY = 0.0,
|
||||
FilterQuality quality = FilterQuality.low]) {
|
||||
@ -105,6 +111,12 @@ void main() {
|
||||
makeBlur(10.0, 10.0, TileMode.decal),
|
||||
makeBlur(10.0, 20.0),
|
||||
makeBlur(20.0, 20.0),
|
||||
makeDilate(10.0, 20.0),
|
||||
makeDilate(20.0, 20.0),
|
||||
makeDilate(20.0, 10.0),
|
||||
makeErode(10.0, 20.0),
|
||||
makeErode(20.0, 20.0),
|
||||
makeErode(20.0, 10.0),
|
||||
makeScale(10.0, 10.0),
|
||||
makeScale(10.0, 20.0),
|
||||
makeScale(20.0, 10.0),
|
||||
@ -170,6 +182,24 @@ void main() {
|
||||
checkBytes(bytes, greenCenterBlurred, greenSideBlurred, greenCornerBlurred);
|
||||
});
|
||||
|
||||
test('ImageFilter - dilate', () async {
|
||||
final Paint paint = Paint()
|
||||
..color = green
|
||||
..imageFilter = makeDilate(1.0, 1.0);
|
||||
|
||||
final Uint32List bytes = await getBytesForPaint(paint);
|
||||
checkBytes(bytes, green.value, green.value, green.value);
|
||||
});
|
||||
|
||||
test('ImageFilter - erode', () async {
|
||||
final Paint paint = Paint()
|
||||
..color = green
|
||||
..imageFilter = makeErode(1.0, 1.0);
|
||||
|
||||
final Uint32List bytes = await getBytesForPaint(paint);
|
||||
checkBytes(bytes, 0, 0, 0);
|
||||
});
|
||||
|
||||
test('ImageFilter - matrix', () async {
|
||||
final Paint paint = Paint()
|
||||
..color = green
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user