FilterParams.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <LibGUI/Action.h>
  8. #include <LibGUI/BoxLayout.h>
  9. #include <LibGUI/Button.h>
  10. #include <LibGUI/CheckBox.h>
  11. #include <LibGUI/Dialog.h>
  12. #include <LibGUI/Menu.h>
  13. #include <LibGUI/Painter.h>
  14. #include <LibGUI/TextBox.h>
  15. #include <LibGfx/Filters/BoxBlurFilter.h>
  16. #include <LibGfx/Filters/GenericConvolutionFilter.h>
  17. #include <LibGfx/Filters/GrayscaleFilter.h>
  18. #include <LibGfx/Filters/InvertFilter.h>
  19. #include <LibGfx/Filters/LaplacianFilter.h>
  20. #include <LibGfx/Filters/SepiaFilter.h>
  21. #include <LibGfx/Filters/SharpenFilter.h>
  22. #include <LibGfx/Filters/SpatialGaussianBlurFilter.h>
  23. namespace PixelPaint {
  24. template<typename Filter>
  25. struct FilterParameters {
  26. };
  27. template<size_t N>
  28. class GenericConvolutionFilterInputDialog : public GUI::Dialog {
  29. C_OBJECT(GenericConvolutionFilterInputDialog);
  30. public:
  31. Matrix<N, float> const& matrix() const { return m_matrix; }
  32. bool should_wrap() const { return m_should_wrap; }
  33. private:
  34. explicit GenericConvolutionFilterInputDialog(GUI::Window* parent_window)
  35. : Dialog(parent_window)
  36. {
  37. // FIXME: Help! Make this GUI less ugly.
  38. StringBuilder builder;
  39. builder.appendff("{}x{}", N, N);
  40. builder.append(" Convolution");
  41. set_title(builder.string_view());
  42. resize(200, 250);
  43. auto& main_widget = set_main_widget<GUI::Frame>();
  44. main_widget.set_frame_shape(Gfx::FrameShape::Container);
  45. main_widget.set_frame_shadow(Gfx::FrameShadow::Raised);
  46. main_widget.set_fill_with_background_color(true);
  47. auto& layout = main_widget.template set_layout<GUI::VerticalBoxLayout>();
  48. layout.set_margins(4);
  49. size_t index = 0;
  50. size_t columns = N;
  51. size_t rows = N;
  52. for (size_t row = 0; row < rows; ++row) {
  53. auto& horizontal_container = main_widget.template add<GUI::Widget>();
  54. horizontal_container.template set_layout<GUI::HorizontalBoxLayout>();
  55. for (size_t column = 0; column < columns; ++column) {
  56. if (index < columns * rows) {
  57. auto& textbox = horizontal_container.template add<GUI::TextBox>();
  58. textbox.on_change = [&, row = row, column = column] {
  59. auto& element = m_matrix.elements()[row][column];
  60. char* endptr = nullptr;
  61. auto value = strtof(textbox.text().characters(), &endptr);
  62. if (endptr != nullptr)
  63. element = value;
  64. else
  65. textbox.set_text("");
  66. };
  67. } else {
  68. horizontal_container.template add<GUI::Widget>();
  69. }
  70. }
  71. }
  72. auto& norm_checkbox = main_widget.template add<GUI::CheckBox>("Normalize");
  73. norm_checkbox.set_checked(false);
  74. auto& wrap_checkbox = main_widget.template add<GUI::CheckBox>("Wrap");
  75. wrap_checkbox.set_checked(m_should_wrap);
  76. auto& button = main_widget.template add<GUI::Button>("Done");
  77. button.on_click = [&](auto) {
  78. m_should_wrap = wrap_checkbox.is_checked();
  79. if (norm_checkbox.is_checked())
  80. normalize(m_matrix);
  81. done(ExecResult::OK);
  82. };
  83. }
  84. Matrix<N, float> m_matrix {};
  85. bool m_should_wrap { false };
  86. };
  87. template<size_t N>
  88. struct FilterParameters<Gfx::SpatialGaussianBlurFilter<N>> {
  89. static OwnPtr<typename Gfx::SpatialGaussianBlurFilter<N>::Parameters> get()
  90. {
  91. constexpr static ssize_t offset = N / 2;
  92. Matrix<N, float> kernel;
  93. auto sigma = 1.0f;
  94. auto s = 2.0f * sigma * sigma;
  95. for (auto x = -offset; x <= offset; x++) {
  96. for (auto y = -offset; y <= offset; y++) {
  97. auto r = sqrtf(x * x + y * y);
  98. kernel.elements()[x + offset][y + offset] = (expf(-(r * r) / s)) / (float { M_PI } * s);
  99. }
  100. }
  101. normalize(kernel);
  102. return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(kernel);
  103. }
  104. };
  105. template<>
  106. struct FilterParameters<Gfx::SharpenFilter> {
  107. static OwnPtr<Gfx::GenericConvolutionFilter<3>::Parameters> get()
  108. {
  109. return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(0, -1, 0, -1, 5, -1, 0, -1, 0));
  110. }
  111. };
  112. template<>
  113. struct FilterParameters<Gfx::LaplacianFilter> {
  114. static OwnPtr<Gfx::GenericConvolutionFilter<3>::Parameters> get(bool diagonal)
  115. {
  116. if (diagonal)
  117. return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(-1, -1, -1, -1, 8, -1, -1, -1, -1));
  118. return make<Gfx::GenericConvolutionFilter<3>::Parameters>(Matrix<3, float>(0, -1, 0, -1, 4, -1, 0, -1, 0));
  119. }
  120. };
  121. template<size_t N>
  122. struct FilterParameters<Gfx::GenericConvolutionFilter<N>> {
  123. static OwnPtr<typename Gfx::GenericConvolutionFilter<N>::Parameters> get(GUI::Window* parent_window)
  124. {
  125. auto input = GenericConvolutionFilterInputDialog<N>::construct(parent_window);
  126. input->exec();
  127. if (input->result() == GUI::Dialog::ExecResult::OK)
  128. return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(input->matrix(), input->should_wrap());
  129. return {};
  130. }
  131. };
  132. template<size_t N>
  133. struct FilterParameters<Gfx::BoxBlurFilter<N>> {
  134. static OwnPtr<typename Gfx::GenericConvolutionFilter<N>::Parameters> get()
  135. {
  136. Matrix<N, float> kernel;
  137. for (size_t i = 0; i < N; ++i) {
  138. for (size_t j = 0; j < N; ++j) {
  139. kernel.elements()[i][j] = 1;
  140. }
  141. }
  142. normalize(kernel);
  143. return make<typename Gfx::GenericConvolutionFilter<N>::Parameters>(kernel);
  144. }
  145. };
  146. }