123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- /*
- * Copyright (c) 2020, the SerenityOS developers.
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #pragma once
- #include <LibGUI/Action.h>
- #include <LibGUI/BoxLayout.h>
- #include <LibGUI/Button.h>
- #include <LibGUI/CheckBox.h>
- #include <LibGUI/Dialog.h>
- #include <LibGUI/Menu.h>
- #include <LibGUI/Painter.h>
- #include <LibGUI/TextBox.h>
- #include <LibGfx/Filters/BoxBlurFilter.h>
- #include <LibGfx/Filters/GenericConvolutionFilter.h>
- #include <LibGfx/Filters/GrayscaleFilter.h>
- #include <LibGfx/Filters/InvertFilter.h>
- #include <LibGfx/Filters/LaplacianFilter.h>
- #include <LibGfx/Filters/SepiaFilter.h>
- #include <LibGfx/Filters/SharpenFilter.h>
- #include <LibGfx/Filters/SpatialGaussianBlurFilter.h>
- namespace PixelPaint {
- template<typename Filter>
- struct FilterParameters {
- };
- template<size_t N>
- class GenericConvolutionFilterInputDialog : public GUI::Dialog {
- C_OBJECT(GenericConvolutionFilterInputDialog);
- public:
- Matrix<N, float> const& matrix() const { return m_matrix; }
- bool should_wrap() const { return m_should_wrap; }
- private:
- explicit GenericConvolutionFilterInputDialog(GUI::Window* parent_window)
- : Dialog(parent_window)
- {
- // FIXME: Help! Make this GUI less ugly.
- StringBuilder builder;
- builder.appendff("{}x{}", N, N);
- builder.append(" Convolution");
- set_title(builder.string_view());
- resize(200, 250);
- auto& main_widget = set_main_widget<GUI::Frame>();
- main_widget.set_frame_shape(Gfx::FrameShape::Container);
- main_widget.set_frame_shadow(Gfx::FrameShadow::Raised);
- main_widget.set_fill_with_background_color(true);
- auto& layout = main_widget.template set_layout<GUI::VerticalBoxLayout>();
- layout.set_margins(4);
- size_t index = 0;
- size_t columns = N;
- size_t rows = N;
- for (size_t row = 0; row < rows; ++row) {
- auto& horizontal_container = main_widget.template add<GUI::Widget>();
- horizontal_container.template set_layout<GUI::HorizontalBoxLayout>();
- for (size_t column = 0; column < columns; ++column) {
- if (index < columns * rows) {
- auto& textbox = horizontal_container.template add<GUI::TextBox>();
- textbox.on_change = [&, row = row, column = column] {
- auto& element = m_matrix.elements()[row][column];
- char* endptr = nullptr;
- auto value = strtof(textbox.text().characters(), &endptr);
- if (endptr != nullptr)
- element = value;
- else
- textbox.set_text("");
- };
- } else {
- horizontal_container.template add<GUI::Widget>();
- }
- }
- }
- auto& norm_checkbox = main_widget.template add<GUI::CheckBox>("Normalize");
- norm_checkbox.set_checked(false);
- auto& wrap_checkbox = main_widget.template add<GUI::CheckBox>("Wrap");
- wrap_checkbox.set_checked(m_should_wrap);
- auto& button = main_widget.template add<GUI::Button>("Done");
- button.on_click = [&](auto) {
- m_should_wrap = wrap_checkbox.is_checked();
- if (norm_checkbox.is_checked())
- normalize(m_matrix);
- done(ExecResult::OK);
- };
- }
- Matrix<N, float> m_matrix {};
- bool m_should_wrap { false };
- };
- template<size_t N>
- struct FilterParameters<Gfx::SpatialGaussianBlurFilter<N>> {
- static OwnPtr<typename Gfx::SpatialGaussianBlurFilter<N>::Parameters> get()
- {
- constexpr static ssize_t offset = N / 2;
- Matrix<N, float> kernel;
- auto sigma = 1.0f;
- auto s = 2.0f * sigma * sigma;
- for (auto x = -offset; x <= offset; x++) {
- for (auto y = -offset; y <= offset; y++) {
- auto r = sqrtf(x * x + y * y);
- kernel.elements()[x + offset][y + offset] = (expf(-(r * r) / s)) / (float { M_PI } * s);
- }
- }
- normalize(kernel);
- return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(kernel);
- }
- };
- template<>
- struct FilterParameters<Gfx::SharpenFilter> {
- static OwnPtr<Gfx::GenericConvolutionFilter<3>::Parameters> get()
- {
- return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(0, -1, 0, -1, 5, -1, 0, -1, 0));
- }
- };
- template<>
- struct FilterParameters<Gfx::LaplacianFilter> {
- static OwnPtr<Gfx::GenericConvolutionFilter<3>::Parameters> get(bool diagonal)
- {
- if (diagonal)
- return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(-1, -1, -1, -1, 8, -1, -1, -1, -1));
- return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(0, -1, 0, -1, 4, -1, 0, -1, 0));
- }
- };
- template<size_t N>
- struct FilterParameters<Gfx::GenericConvolutionFilter<N>> {
- static OwnPtr<typename Gfx::GenericConvolutionFilter<N>::Parameters> get(GUI::Window* parent_window)
- {
- auto input = GenericConvolutionFilterInputDialog<N>::construct(parent_window);
- input->exec();
- if (input->result() == GUI::Dialog::ExecResult::OK)
- return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(input->matrix(), input->should_wrap());
- return {};
- }
- };
- template<size_t N>
- struct FilterParameters<Gfx::BoxBlurFilter<N>> {
- static OwnPtr<typename Gfx::GenericConvolutionFilter<N>::Parameters> get()
- {
- Matrix<N, float> kernel;
- for (size_t i = 0; i < N; ++i) {
- for (size_t j = 0; j < N; ++j) {
- kernel.elements()[i][j] = 1;
- }
- }
- normalize(kernel);
- return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(kernel);
- }
- };
- }
|