1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 07:07: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,27 +16,24 @@
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();
if (intermediate_bitmap_or_error.is_error())
return;
if (auto* layer = m_editor->active_layer()) {
auto intermediate_bitmap_or_error = layer->bitmap().clone();
if (intermediate_bitmap_or_error.is_error())
return;
auto intermediate_bitmap = intermediate_bitmap_or_error.release_value();
auto intermediate_bitmap = intermediate_bitmap_or_error.release_value();
Gfx::LumaFilter luma_filter(intermediate_bitmap);
luma_filter.apply(m_luma_lower, 255);
Gfx::LumaFilter luma_filter(intermediate_bitmap);
luma_filter.apply(m_luma_lower, 255);
Gfx::FastBoxBlurFilter blur_filter(intermediate_bitmap);
blur_filter.apply_three_passes(m_blur_radius);
Gfx::FastBoxBlurFilter blur_filter(intermediate_bitmap);
blur_filter.apply_three_passes(m_blur_radius);
Gfx::BitmapMixer mixer(layer->bitmap());
mixer.mix_with(intermediate_bitmap, Gfx::BitmapMixer::MixingMethod::Lightest);
}
Gfx::BitmapMixer mixer(target_bitmap);
mixer.mix_with(intermediate_bitmap, Gfx::BitmapMixer::MixingMethod::Lightest);
}
RefPtr<GUI::Widget> Bloom::get_settings_widget()
{
if (!m_settings_widget) {

View file

@ -12,7 +12,8 @@ namespace PixelPaint::Filters {
class Bloom final : public Filter {
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 StringView filter_name() override { return "Bloom Filter"sv; }

View file

@ -9,18 +9,11 @@
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;
if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<3>>::get()) {
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
Gfx::BoxBlurFilter<3> filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<3>>::get())
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
}
}

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class BoxBlur3 final : public Filter {
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; }
BoxBlur3(ImageEditor* editor)

View file

@ -9,18 +9,11 @@
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;
if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<5>>::get()) {
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
Gfx::BoxBlurFilter<5> filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::BoxBlurFilter<5>>::get())
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
}
}

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class BoxBlur5 final : public Filter {
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; }
BoxBlur5(ImageEditor* editor)

View file

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

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class FastBoxBlur final : public Filter {
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 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, Mustafa Quraish <mustafa@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -25,4 +26,15 @@ RefPtr<GUI::Widget> Filter::get_settings_widget()
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, Mustafa Quraish <mustafa@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -14,7 +15,9 @@ namespace PixelPaint {
class Filter {
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 StringView filter_name() = 0;

View file

@ -9,18 +9,11 @@
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;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<3>>::get()) {
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
Gfx::SpatialGaussianBlurFilter<3> filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<3>>::get())
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
}
}

View file

@ -13,7 +13,7 @@ namespace PixelPaint::Filters {
// FIXME: Make a generic gaussian blur that does not need the templated radius
class GaussBlur3 final : public Filter {
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; }
GaussBlur3(ImageEditor* editor)

View file

@ -9,18 +9,11 @@
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;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<5>>::get()) {
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
Gfx::SpatialGaussianBlurFilter<5> filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SpatialGaussianBlurFilter<5>>::get())
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
}
}

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class GaussBlur5 final : public Filter {
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; }
GaussBlur5(ImageEditor* editor)

View file

@ -9,16 +9,10 @@
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;
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect());
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
Gfx::GrayscaleFilter filter;
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect());
}
}

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class Grayscale final : public Filter {
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; }
Grayscale(ImageEditor* editor)

View file

@ -9,16 +9,10 @@
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;
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect());
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
Gfx::InvertFilter filter;
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect());
}
}

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class Invert final : public Filter {
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; }
Invert(ImageEditor* editor)

View file

@ -9,18 +9,11 @@
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;
if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(false)) {
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
Gfx::LaplacianFilter filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(false))
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
}
}

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class LaplaceCardinal final : public Filter {
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; }
LaplaceCardinal(ImageEditor* editor)

View file

@ -9,18 +9,11 @@
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;
if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(true)) {
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
Gfx::LaplacianFilter filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::LaplacianFilter>::get(true))
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
}
}

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class LaplaceDiagonal final : public Filter {
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; }
LaplaceDiagonal(ImageEditor* editor)

View file

@ -11,16 +11,10 @@
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);
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect());
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
Gfx::SepiaFilter filter(m_amount);
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect());
}
RefPtr<GUI::Widget> Sepia::get_settings_widget()

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class Sepia final : public Filter {
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 StringView filter_name() override { return "Sepia"sv; }

View file

@ -9,18 +9,11 @@
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;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SharpenFilter>::get()) {
filter.apply(layer->bitmap(), layer->rect(), layer->bitmap(), layer->rect(), *parameters);
layer->did_modify_bitmap(layer->rect());
m_editor->did_complete_action();
}
}
Gfx::SharpenFilter filter;
if (auto parameters = PixelPaint::FilterParameters<Gfx::SharpenFilter>::get())
filter.apply(target_bitmap, target_bitmap.rect(), source_bitmap, source_bitmap.rect(), *parameters);
}
}

View file

@ -12,7 +12,7 @@ namespace PixelPaint::Filters {
class Sharpen final : public Filter {
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; }
Sharpen(ImageEditor* editor)