summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorMacDue <macdue@dueutil.tech>2022-10-01 22:42:31 +0100
committerAndreas Kling <kling@serenityos.org>2022-10-02 21:17:41 +0200
commitdf6b7fff905ed8a71e70f099bc317bf6cc4671ce (patch)
tree1ef1a58c84e0282d05cada5c941a03ffc9fa2fc0 /Userland
parent6b167c842772e8096a606e3321c16bc9d7283613 (diff)
downloadserenity-df6b7fff905ed8a71e70f099bc317bf6cc4671ce.zip
LibGfx: Implement HueRotateFilter
This implements a simple and fairly efficient hue rotation filter. It is based off the SVG feColorMatrix "hueRotate" matrix operation. https://drafts.fxtf.org/filter-effects-1/#elementdef-fecolormatrix
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibGfx/Filters/HueRotateFilter.h84
1 files changed, 84 insertions, 0 deletions
diff --git a/Userland/Libraries/LibGfx/Filters/HueRotateFilter.h b/Userland/Libraries/LibGfx/Filters/HueRotateFilter.h
new file mode 100644
index 0000000000..a4350ded35
--- /dev/null
+++ b/Userland/Libraries/LibGfx/Filters/HueRotateFilter.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2022, MacDue <macdue@dueutil.tech>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Math.h>
+#include <LibGfx/Filters/ColorFilter.h>
+#include <LibGfx/Matrix3x3.h>
+
+namespace Gfx {
+
+class HueRotateFilter : public ColorFilter {
+public:
+ HueRotateFilter(float angle_degrees)
+ : ColorFilter(angle_degrees)
+ , m_operation(calculate_operation_matrix(angle_degrees))
+ {
+ }
+
+ virtual bool amount_handled_in_filter() const override
+ {
+ return true;
+ }
+
+ float angle_degrees() const
+ {
+ return m_amount;
+ }
+
+ virtual StringView class_name() const override { return "HueRotateFilter"sv; }
+
+protected:
+ Color convert_color(Color original) override
+ {
+ FloatVector3 rgb = {
+ original.red() / 256.0f,
+ original.green() / 256.0f,
+ original.blue() / 256.0f,
+ };
+ rgb = m_operation * rgb;
+ auto safe_float_to_u8 = [](float value) -> u8 {
+ return static_cast<u8>(AK::clamp(value, 0.0f, 1.0f) * 256);
+ };
+ return Color {
+ safe_float_to_u8(rgb[0]),
+ safe_float_to_u8(rgb[1]),
+ safe_float_to_u8(rgb[2]),
+ original.alpha()
+ };
+ }
+
+private:
+ static FloatMatrix3x3 calculate_operation_matrix(float angle)
+ {
+ float angle_rads = angle * (AK::Pi<float> / 180);
+ float cos_angle = 0;
+ float sin_angle = 0;
+ AK::sincos(angle_rads, sin_angle, cos_angle);
+ // The matrices here are taken directly from the SVG filter specification:
+ // https://drafts.fxtf.org/filter-effects-1/#feColorMatrixElement
+ // clang-format off
+ return FloatMatrix3x3 {
+ +0.213, +0.715, +0.072,
+ +0.213, +0.715, +0.072,
+ +0.213, +0.715, +0.072
+ } + cos_angle * FloatMatrix3x3 {
+ +0.787, -0.715, -0.072,
+ -0.213, +0.285, -0.072,
+ -0.213, -0.715, +0.928
+ } + sin_angle * FloatMatrix3x3 {
+ -0.213, -0.715, +0.928,
+ +0.143, +0.140, -0.283,
+ -0.787, +0.715, +0.072
+ };
+ // clang-format on
+ }
+
+ FloatMatrix3x3 m_operation;
+};
+
+}