aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2021-02-10 15:43:01 +0100
committerFelix Morgner <felix.morgner@gmail.com>2021-02-10 15:56:18 +0100
commitd70aaf0ef92cac0781dabb60411bbd907e7f0caa (patch)
tree949115e3b3d0c117d83af7c0924322084e178fbf
parent4fc2b7acffb9699c3ef4fbe5027124e589735be0 (diff)
downloadwanda-d70aaf0ef92cac0781dabb60411bbd907e7f0caa.tar.xz
wanda-d70aaf0ef92cac0781dabb60411bbd907e7f0caa.zip
wallpaper: calculate average color
-rw-r--r--CMakeLists.txt11
-rw-r--r--conanfile.py3
-rw-r--r--include/wanda/magic.hpp58
-rw-r--r--src/wanda/wallpaper.cpp72
4 files changed, 144 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fe0f53..f0a95f0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -58,6 +58,13 @@ pkg_check_modules("GIO"
"gio-2.0"
)
+pkg_check_modules("libmagic"
+ REQUIRED
+ IMPORTED_TARGET
+ GLOBAL
+ "libmagic"
+)
+
find_library(C++FS_LIBRARIES
"stdc++fs"
DOC "The C++ Standard Library Filesystem implementation"
@@ -115,7 +122,11 @@ add_executable("${PROJECT_NAME}d"
target_link_libraries("${PROJECT_NAME}d"
"${PROJECT_NAME}"
"CONAN_PKG::lyra"
+ "CONAN_PKG::boost"
+ "CONAN_PKG::libjpeg"
+ "CONAN_PKG::libpng"
"PkgConfig::GIO"
+ "PkgConfig::libmagic"
)
add_executable("${PROJECT_NAME}c"
diff --git a/conanfile.py b/conanfile.py
index 1635cb6..df70efb 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -29,6 +29,9 @@ class Wanda(ConanFile):
"lyra/1.5.1",
"CUTE/2.2.6@fmorgner/stable",
"spdlog/1.4.2",
+ "boost/1.75.0",
+ "libpng/1.6.37",
+ "libjpeg/9d",
)
def configure_cmake(self):
diff --git a/include/wanda/magic.hpp b/include/wanda/magic.hpp
new file mode 100644
index 0000000..fcb153e
--- /dev/null
+++ b/include/wanda/magic.hpp
@@ -0,0 +1,58 @@
+#ifndef WANDA_MAGIC_HPP
+#define WANDA_MAGIC_HPP
+
+#include <magic.h>
+
+#include <filesystem>
+#include <memory>
+#include <string>
+#include <type_traits>
+
+namespace wanda
+{
+ struct magic
+ {
+ struct closer
+ {
+ auto operator()(magic_t handle) const noexcept -> void
+ {
+ magic_close(handle);
+ }
+ };
+
+ enum struct mime_type
+ {
+ unknown,
+ image_jpeg,
+ image_png,
+ };
+
+ magic()
+ : m_handle{magic_open(MAGIC_MIME_TYPE)}
+ {
+ magic_load(m_handle.get(), nullptr);
+ }
+
+ auto type(std::filesystem::path path) -> mime_type
+ {
+ auto magic_type = std::string{magic_file(m_handle.get(), path.native().c_str())};
+
+ if (magic_type == "image/jpeg")
+ {
+ return mime_type::image_jpeg;
+ }
+ else if (magic_type == "image/png")
+ {
+ return mime_type::image_png;
+ }
+
+ return mime_type::unknown;
+ }
+
+ private:
+ std::unique_ptr<std::remove_pointer_t<magic_t>, closer> m_handle;
+ };
+
+} // namespace wanda
+
+#endif \ No newline at end of file
diff --git a/src/wanda/wallpaper.cpp b/src/wanda/wallpaper.cpp
index 3fc93b3..7d4c7d5 100644
--- a/src/wanda/wallpaper.cpp
+++ b/src/wanda/wallpaper.cpp
@@ -1,17 +1,89 @@
#include <wanda/logging.hpp>
+#include <wanda/magic.hpp>
#include <wanda/optional.hpp>
#include <wanda/setting.hpp>
#include <wanda/wallpaper.hpp>
+#include <boost/gil.hpp>
+#include <boost/gil/extension/io/jpeg.hpp>
+#include <boost/gil/extension/io/png.hpp>
+#include <boost/gil/extension/numeric/resample.hpp>
+#include <boost/gil/extension/numeric/sampler.hpp>
+
+#include <fmt/format.h>
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+
namespace wanda
{
+ namespace
+ {
+ auto magic_instance = magic{};
+
+ auto load_image(std::filesystem::path wallpaper)
+ {
+ auto image = boost::gil::rgb8_image_t{};
+
+ switch (magic_instance.type(wallpaper))
+ {
+ case magic::mime_type::image_jpeg:
+ boost::gil::read_and_convert_image(wallpaper.native(), image, boost::gil::jpeg_tag{});
+ break;
+ case magic::mime_type::image_png:
+ boost::gil::read_and_convert_image(wallpaper.native(), image, boost::gil::png_tag{});
+ break;
+ }
+
+ return image;
+
+ // // auto source_view = ;
+
+ // return fmt::format("#{:02X}{:02X}{:02X}",
+ // static_cast<uint8_t>(std::sqrt((at_c<0>(pixel64) / image.size()))),
+ // static_cast<uint8_t>(std::sqrt((at_c<1>(pixel64) / image.size()))),
+ // static_cast<uint8_t>(std::sqrt((at_c<2>(pixel64) / image.size()))));
+ }
+
+ auto average_colors(boost::gil::rgb8_image_t image)
+ {
+ auto accumulator = boost::gil::rgb64f_pixel_t{};
+ auto view = const_view(image);
+
+ std::ranges::for_each(view, [&](auto const & source_pixel) {
+ at_c<0>(accumulator) += std::pow(boost::gil::at_c<0>(source_pixel), 2);
+ at_c<1>(accumulator) += std::pow(boost::gil::at_c<1>(source_pixel), 2);
+ at_c<2>(accumulator) += std::pow(boost::gil::at_c<2>(source_pixel), 2);
+ });
+
+ at_c<0>(accumulator) = std::sqrt(at_c<0>(accumulator) / view.size());
+ at_c<1>(accumulator) = std::sqrt(at_c<1>(accumulator) / view.size());
+ at_c<2>(accumulator) = std::sqrt(at_c<2>(accumulator) / view.size());
+
+ return accumulator;
+ }
+
+ //
+ } // namespace
+
void set_wallpaper(std::filesystem::path wallpaper)
{
using namespace wanda::literals;
using namespace wanda::std_ext;
using namespace std::string_literals;
+ auto image = load_image(wallpaper);
+ auto color = average_colors(std::move(image));
+ auto hexstring = fmt::format("#{:02X}{:02X}{:02X}",
+ static_cast<std::uint8_t>(at_c<0>(color)),
+ static_cast<std::uint8_t>(at_c<1>(color)),
+ static_cast<std::uint8_t>(at_c<2>(color)));
+
with("org.gnome.desktop.background"_setting, [&](auto & setting) {
+ with(setting["primary-color"_key], [&](auto & value) {
+ value = hexstring;
+ });
with(setting["picture-uri"_key], [&](auto & value) {
value = "file://" + wallpaper.native();
}) ||