Переглянути джерело

PixelPaint+LibGfx: Add sepia color filter

Xavier Defrang 3 роки тому
батько
коміт
b1a15b02f1

+ 1 - 0
Userland/Applications/PixelPaint/CMakeLists.txt

@@ -28,6 +28,7 @@ set(SOURCES
     Filters/Invert.cpp
     Filters/Invert.cpp
     Filters/LaplaceCardinal.cpp
     Filters/LaplaceCardinal.cpp
     Filters/LaplaceDiagonal.cpp
     Filters/LaplaceDiagonal.cpp
+    Filters/Sepia.cpp
     Filters/Sharpen.cpp
     Filters/Sharpen.cpp
     Image.cpp
     Image.cpp
     ImageEditor.cpp
     ImageEditor.cpp

+ 2 - 0
Userland/Applications/PixelPaint/FilterModel.cpp

@@ -17,6 +17,7 @@
 #include "Filters/Invert.h"
 #include "Filters/Invert.h"
 #include "Filters/LaplaceCardinal.h"
 #include "Filters/LaplaceCardinal.h"
 #include "Filters/LaplaceDiagonal.h"
 #include "Filters/LaplaceDiagonal.h"
+#include "Filters/Sepia.h"
 #include "Filters/Sharpen.h"
 #include "Filters/Sharpen.h"
 #include "Layer.h"
 #include "Layer.h"
 #include <LibGUI/FileIconProvider.h>
 #include <LibGUI/FileIconProvider.h>
@@ -48,6 +49,7 @@ FilterModel::FilterModel(ImageEditor* editor)
     auto color_category = FilterInfo::create_category("Color");
     auto color_category = FilterInfo::create_category("Color");
     auto grayscale_filter = FilterInfo::create_filter<Filters::Grayscale>(editor, color_category);
     auto grayscale_filter = FilterInfo::create_filter<Filters::Grayscale>(editor, color_category);
     auto invert_filter = FilterInfo::create_filter<Filters::Invert>(editor, color_category);
     auto invert_filter = FilterInfo::create_filter<Filters::Invert>(editor, color_category);
+    auto sepia_filter = FilterInfo::create_filter<Filters::Sepia>(editor, color_category);
 
 
     m_filters.append(color_category);
     m_filters.append(color_category);
 
 

+ 1 - 0
Userland/Applications/PixelPaint/FilterParams.h

@@ -19,6 +19,7 @@
 #include <LibGfx/Filters/GrayscaleFilter.h>
 #include <LibGfx/Filters/GrayscaleFilter.h>
 #include <LibGfx/Filters/InvertFilter.h>
 #include <LibGfx/Filters/InvertFilter.h>
 #include <LibGfx/Filters/LaplacianFilter.h>
 #include <LibGfx/Filters/LaplacianFilter.h>
+#include <LibGfx/Filters/SepiaFilter.h>
 #include <LibGfx/Filters/SharpenFilter.h>
 #include <LibGfx/Filters/SharpenFilter.h>
 #include <LibGfx/Filters/SpatialGaussianBlurFilter.h>
 #include <LibGfx/Filters/SpatialGaussianBlurFilter.h>
 
 

+ 57 - 0
Userland/Applications/PixelPaint/Filters/Sepia.cpp

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2022, Xavier Defrang <xavier.defrang@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "Sepia.h"
+#include "../FilterParams.h"
+#include <LibGUI/Label.h>
+#include <LibGUI/ValueSlider.h>
+
+namespace PixelPaint::Filters {
+
+void Sepia::apply() 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();
+    }
+}
+
+RefPtr<GUI::Widget> Sepia::get_settings_widget()
+{
+    if (!m_settings_widget) {
+        m_settings_widget = GUI::Widget::construct();
+        m_settings_widget->set_layout<GUI::VerticalBoxLayout>();
+
+        auto& name_label = m_settings_widget->add<GUI::Label>("Sepia Filter");
+        name_label.set_font_weight(Gfx::FontWeight::Bold);
+        name_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
+        name_label.set_fixed_height(20);
+
+        auto& amount_container = m_settings_widget->add<GUI::Widget>();
+        amount_container.set_fixed_height(20);
+        amount_container.set_layout<GUI::HorizontalBoxLayout>();
+        amount_container.layout()->set_margins({ 4, 0, 4, 0 });
+
+        auto& amount_label = amount_container.add<GUI::Label>("Amount:");
+        amount_label.set_text_alignment(Gfx::TextAlignment::CenterLeft);
+        amount_label.set_fixed_size(50, 20);
+
+        auto& amount_slider = amount_container.add<GUI::ValueSlider>(Orientation::Horizontal, "%");
+        amount_slider.set_range(0, 100);
+        amount_slider.set_value(m_amount * 100);
+        amount_slider.on_change = [&](int value) {
+            m_amount = value * 0.01f;
+        };
+    }
+
+    return m_settings_widget;
+}
+
+}

+ 27 - 0
Userland/Applications/PixelPaint/Filters/Sepia.h

@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022, Xavier Defrang <xavier.defrang@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include "Filter.h"
+
+namespace PixelPaint::Filters {
+
+class Sepia final : public Filter {
+public:
+    virtual void apply() const override;
+    virtual RefPtr<GUI::Widget> get_settings_widget() override;
+
+    virtual StringView filter_name() override { return "Sepia"sv; }
+
+    Sepia(ImageEditor* editor)
+        : Filter(editor) {};
+
+private:
+    float m_amount { 1.0f };
+};
+
+}

+ 27 - 0
Userland/Libraries/LibGfx/Color.h

@@ -232,6 +232,33 @@ public:
         return Color(gray, gray, gray, alpha());
         return Color(gray, gray, gray, alpha());
     }
     }
 
 
+    constexpr Color sepia(float amount = 1.0f) const
+    {
+        auto blend_factor = 1.0f - amount;
+
+        auto r1 = 0.393f + 0.607f * blend_factor;
+        auto r2 = 0.769f - 0.769f * blend_factor;
+        auto r3 = 0.189f - 0.189f * blend_factor;
+
+        auto g1 = 0.349f - 0.349f * blend_factor;
+        auto g2 = 0.686f + 0.314f * blend_factor;
+        auto g3 = 0.168f - 0.168f * blend_factor;
+
+        auto b1 = 0.272f - 0.272f * blend_factor;
+        auto b2 = 0.534f - 0.534f * blend_factor;
+        auto b3 = 0.131f + 0.869f * blend_factor;
+
+        auto r = red();
+        auto g = green();
+        auto b = blue();
+
+        return Color(
+            clamp(lroundf(r * r1 + g * r2 + b * r3), 0, 255),
+            clamp(lroundf(r * g1 + g * g2 + b * g3), 0, 255),
+            clamp(lroundf(r * b1 + g * b2 + b * b3), 0, 255),
+            alpha());
+    }
+
     constexpr Color darkened(float amount = 0.5f) const
     constexpr Color darkened(float amount = 0.5f) const
     {
     {
         return Color(red() * amount, green() * amount, blue() * amount, alpha());
         return Color(red() * amount, green() * amount, blue() * amount, alpha());

+ 32 - 0
Userland/Libraries/LibGfx/Filters/SepiaFilter.h

@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022, Xavier Defrang <xavier.defrang@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/StdLibExtras.h>
+#include <LibGfx/Filters/ColorFilter.h>
+#include <math.h>
+
+namespace Gfx {
+
+class SepiaFilter : public ColorFilter {
+public:
+    SepiaFilter(float amount = 1.0f)
+        : m_amount(amount)
+    {
+    }
+    virtual ~SepiaFilter() { }
+
+    virtual char const* class_name() const override { return "SepiaFilter"; }
+
+protected:
+    Color convert_color(Color original) override { return original.sepia(m_amount); };
+
+private:
+    float m_amount;
+};
+
+}