1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 04:57:45 +00:00

PixelPaint: Move out common logic from Filters into base class

Now, each new filter only has to describe how to actually change
the bitmaps, and the common logic of pulling out the bitmap from the
layer, and marking the action as done, etc is all handled in the
`Filter` base class.

This also makes it possible to apply filters to external bitmaps,
which are not embedded in a `Layer` (which we can use to preview
filters in the future!)
This commit is contained in:
Mustafa Quraish 2022-01-08 21:23:17 -05:00 committed by Andreas Kling
parent 5c0c126122
commit 0e6576b376
26 changed files with 90 additions and 144 deletions

View file

@ -16,12 +16,9 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void Bloom::apply() const void Bloom::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor) auto intermediate_bitmap_or_error = source_bitmap.clone();
return;
if (auto* layer = m_editor->active_layer()) {
auto intermediate_bitmap_or_error = layer->bitmap().clone();
if (intermediate_bitmap_or_error.is_error()) if (intermediate_bitmap_or_error.is_error())
return; return;
@ -33,10 +30,10 @@ void Bloom::apply() const
Gfx::FastBoxBlurFilter blur_filter(intermediate_bitmap); Gfx::FastBoxBlurFilter blur_filter(intermediate_bitmap);
blur_filter.apply_three_passes(m_blur_radius); blur_filter.apply_three_passes(m_blur_radius);
Gfx::BitmapMixer mixer(layer->bitmap()); Gfx::BitmapMixer mixer(target_bitmap);
mixer.mix_with(intermediate_bitmap, Gfx::BitmapMixer::MixingMethod::Lightest); mixer.mix_with(intermediate_bitmap, Gfx::BitmapMixer::MixingMethod::Lightest);
}
} }
RefPtr<GUI::Widget> Bloom::get_settings_widget() RefPtr<GUI::Widget> Bloom::get_settings_widget()
{ {
if (!m_settings_widget) { if (!m_settings_widget) {

View file

@ -12,7 +12,8 @@ namespace PixelPaint::Filters {
class Bloom final : public Filter { class Bloom final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual RefPtr<GUI::Widget> get_settings_widget() override; virtual RefPtr<GUI::Widget> get_settings_widget() override;
virtual StringView filter_name() override { return "Bloom Filter"sv; } virtual StringView filter_name() override { return "Bloom Filter"sv; }

View file

@ -9,18 +9,11 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void BoxBlur3::apply() const void BoxBlur3::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::BoxBlurFilter<3> filter; Gfx::BoxBlurFilter<3> filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<3>>::get()) { if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<3>>::get())
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
} }
} }

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class BoxBlur3 final : public Filter { class BoxBlur3 final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Box Blur (3x3)"sv; } virtual StringView filter_name() override { return "Box Blur (3x3)"sv; }
BoxBlur3(ImageEditor* editor) BoxBlur3(ImageEditor* editor)

View file

@ -9,18 +9,11 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void BoxBlur5::apply() const void BoxBlur5::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::BoxBlurFilter<5> filter; Gfx::BoxBlurFilter<5> filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<5>>::get()) { if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<5>>::get())
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
} }
} }

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class BoxBlur5 final : public Filter { class BoxBlur5 final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Box Blur (5x5)"sv; } virtual StringView filter_name() override { return "Box Blur (5x5)"sv; }
BoxBlur5(ImageEditor* editor) BoxBlur5(ImageEditor* editor)

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org> * Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2022, Mustafa Quraish <mustafa@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -12,21 +13,20 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void FastBoxBlur::apply() const void FastBoxBlur::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor) // This filter only works in-place, so if we have different target and source, we first copy over
return; // the source bitmap to the target one.
if (auto* layer = m_editor->active_layer()) { if (&target_bitmap != &source_bitmap) {
Gfx::FastBoxBlurFilter filter(layer->bitmap()); VERIFY(source_bitmap.size_in_bytes() == target_bitmap.size_in_bytes());
memcpy(target_bitmap.scanline(0), source_bitmap.scanline(0), source_bitmap.size_in_bytes());
}
Gfx::FastBoxBlurFilter filter(target_bitmap);
if (m_approximate_gauss) if (m_approximate_gauss)
filter.apply_three_passes(m_radius); filter.apply_three_passes(m_radius);
else else
filter.apply_single_pass(m_radius); filter.apply_single_pass(m_radius);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
} }
RefPtr<GUI::Widget> FastBoxBlur::get_settings_widget() RefPtr<GUI::Widget> FastBoxBlur::get_settings_widget()

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class FastBoxBlur final : public Filter { class FastBoxBlur final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual RefPtr<GUI::Widget> get_settings_widget() override; virtual RefPtr<GUI::Widget> get_settings_widget() override;
virtual StringView filter_name() override { return "Fast Box Blur (& Gauss)"sv; } virtual StringView filter_name() override { return "Fast Box Blur (& Gauss)"sv; }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org> * Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2022, Mustafa Quraish <mustafa@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -25,4 +26,15 @@ RefPtr<GUI::Widget> Filter::get_settings_widget()
return m_settings_widget.ptr(); return m_settings_widget.ptr();
} }
void Filter::apply() const
{
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
apply(layer->bitmap(), layer->bitmap());
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
} }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org> * Copyright (c) 2022, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2022, Mustafa Quraish <mustafa@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -14,7 +15,9 @@ namespace PixelPaint {
class Filter { class Filter {
public: public:
virtual void apply() const = 0; virtual void apply() const;
virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const = 0;
virtual RefPtr<GUI::Widget> get_settings_widget(); virtual RefPtr<GUI::Widget> get_settings_widget();
virtual StringView filter_name() = 0; virtual StringView filter_name() = 0;

View file

@ -9,18 +9,11 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void GaussBlur3::apply() const void GaussBlur3::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::SpatialGaussianBlurFilter<3> filter; Gfx::SpatialGaussianBlurFilter<3> filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<3>>::get()) { if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<3>>::get())
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
} }
} }

View file

@ -13,7 +13,7 @@ namespace PixelPaint::Filters {
// FIXME: Make a generic gaussian blur that does not need the templated radius // FIXME: Make a generic gaussian blur that does not need the templated radius
class GaussBlur3 final : public Filter { class GaussBlur3 final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Gaussian Blur (3x3)"sv; } virtual StringView filter_name() override { return "Gaussian Blur (3x3)"sv; }
GaussBlur3(ImageEditor* editor) GaussBlur3(ImageEditor* editor)

View file

@ -9,18 +9,11 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void GaussBlur5::apply() const void GaussBlur5::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::SpatialGaussianBlurFilter<5> filter; Gfx::SpatialGaussianBlurFilter<5> filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<5>>::get()) { if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<5>>::get())
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
} }
} }

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class GaussBlur5 final : public Filter { class GaussBlur5 final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Gaussian Blur (5x5)"sv; } virtual StringView filter_name() override { return "Gaussian Blur (5x5)"sv; }
GaussBlur5(ImageEditor* editor) GaussBlur5(ImageEditor* editor)

View file

@ -9,16 +9,10 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void Grayscale::apply() const void Grayscale::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::GrayscaleFilter filter; Gfx::GrayscaleFilter filter;
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect()); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect());
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
} }
} }

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class Grayscale final : public Filter { class Grayscale final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Grayscale"sv; } virtual StringView filter_name() override { return "Grayscale"sv; }
Grayscale(ImageEditor* editor) Grayscale(ImageEditor* editor)

View file

@ -9,16 +9,10 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void Invert::apply() const void Invert::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::InvertFilter filter; Gfx::InvertFilter filter;
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect()); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect());
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
} }
} }

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class Invert final : public Filter { class Invert final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Invert"sv; } virtual StringView filter_name() override { return "Invert"sv; }
Invert(ImageEditor* editor) Invert(ImageEditor* editor)

View file

@ -9,18 +9,11 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void LaplaceCardinal::apply() const void LaplaceCardinal::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::LaplacianFilter filter; Gfx::LaplacianFilter filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(false)) { if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(false))
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
} }
} }

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class LaplaceCardinal final : public Filter { class LaplaceCardinal final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Laplacian Cardinal"sv; } virtual StringView filter_name() override { return "Laplacian Cardinal"sv; }
LaplaceCardinal(ImageEditor* editor) LaplaceCardinal(ImageEditor* editor)

View file

@ -9,18 +9,11 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void LaplaceDiagonal::apply() const void LaplaceDiagonal::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::LaplacianFilter filter; Gfx::LaplacianFilter filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(true)) { if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(true))
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
} }
} }

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class LaplaceDiagonal final : public Filter { class LaplaceDiagonal final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Laplacian Diagonal"sv; } virtual StringView filter_name() override { return "Laplacian Diagonal"sv; }
LaplaceDiagonal(ImageEditor* editor) LaplaceDiagonal(ImageEditor* editor)

View file

@ -11,16 +11,10 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void Sepia::apply() const void Sepia::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::SepiaFilter filter(m_amount); Gfx::SepiaFilter filter(m_amount);
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect()); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect());
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
} }
RefPtr<GUI::Widget> Sepia::get_settings_widget() RefPtr<GUI::Widget> Sepia::get_settings_widget()

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class Sepia final : public Filter { class Sepia final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual RefPtr<GUI::Widget> get_settings_widget() override; virtual RefPtr<GUI::Widget> get_settings_widget() override;
virtual StringView filter_name() override { return "Sepia"sv; } virtual StringView filter_name() override { return "Sepia"sv; }

View file

@ -9,18 +9,11 @@
namespace PixelPaint::Filters { namespace PixelPaint::Filters {
void Sharpen::apply() const void Sharpen::apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const
{ {
if (!m_editor)
return;
if (auto* layer = m_editor->active_layer()) {
Gfx::SharpenFilter filter; Gfx::SharpenFilter filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SharpenFilter>::get()) { if (auto parameters = PixelPaint::FilterParameters<Gfx::SharpenFilter>::get())
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters); filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
} }
} }

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class Sharpen final : public Filter { class Sharpen final : public Filter {
public: public:
virtual void apply() const override; virtual void apply(Gfx::Bitmap& target_bitmap, Gfx::Bitmap const& source_bitmap) const override;
virtual StringView filter_name() override { return "Sharpen"sv; } virtual StringView filter_name() override { return "Sharpen"sv; }
Sharpen(ImageEditor* editor) Sharpen(ImageEditor* editor)