Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package hyprgraphics for openSUSE:Factory 
checked in at 2025-06-05 20:34:47
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/hyprgraphics (Old)
 and      /work/SRC/openSUSE:Factory/.hyprgraphics.new.19631 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "hyprgraphics"

Thu Jun  5 20:34:47 2025 rev:2 rq:1283006 version:0.1.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/hyprgraphics/hyprgraphics.changes        
2024-12-18 20:11:34.620892570 +0100
+++ /work/SRC/openSUSE:Factory/.hyprgraphics.new.19631/hyprgraphics.changes     
2025-06-05 20:37:25.132976445 +0200
@@ -1,0 +2,17 @@
+Fri May  9 09:59:41 UTC 2025 - Florian "sp1rit" <[email protected]>
+
+- Update to version 0.1.3:
+  + A minor update with some fixes and new CM-related math
+  + Additions:
+    - CM structs, constants & math
+
+- Changes from version 0.1.2:
+  + This release adds a few small fixes, and moves to a more robust
+    and fast png parser.
+  + Changes:
+    - move to libspng for png parsing
+    - Allow compiling without JXL support
+  + Fixes:
+    - add symlink support for image
+
+-------------------------------------------------------------------

Old:
----
  hyprgraphics-0.1.1.tar.xz

New:
----
  hyprgraphics-0.1.3.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ hyprgraphics.spec ++++++
--- /var/tmp/diff_new_pack.RAFIks/_old  2025-06-05 20:37:25.628997069 +0200
+++ /var/tmp/diff_new_pack.RAFIks/_new  2025-06-05 20:37:25.628997069 +0200
@@ -19,7 +19,7 @@
 %define sover 0
 
 Name:           hyprgraphics
-Version:        0.1.1
+Version:        0.1.3
 Release:        0
 Summary:        Hyprland graphics / resource utilities
 License:        BSD-3-Clause
@@ -37,6 +37,7 @@
 BuildRequires:  pkgconfig(libmagic)
 BuildRequires:  pkgconfig(libwebp)
 BuildRequires:  pkgconfig(pixman-1)
+BuildRequires:  pkgconfig(spng)
 
 %define _description %{expand:
 Hyprgraphics is a small C++ library with graphics / resource related

++++++ hyprgraphics-0.1.1.tar.xz -> hyprgraphics-0.1.3.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/.github/workflows/arch.yml 
new/hyprgraphics-0.1.3/.github/workflows/arch.yml
--- old/hyprgraphics-0.1.1/.github/workflows/arch.yml   2024-12-03 
18:52:51.000000000 +0100
+++ new/hyprgraphics-0.1.3/.github/workflows/arch.yml   2025-04-06 
17:28:42.000000000 +0200
@@ -17,7 +17,7 @@
         run: |
           sed -i 's/SigLevel    = Required DatabaseOptional/SigLevel    = 
Optional TrustAll/' /etc/pacman.conf
           pacman --noconfirm --noprogressbar -Syyu
-          pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang 
libc++ pixman cairo hyprutils libjpeg-turbo libjxl libwebp
+          pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang 
libc++ pixman cairo hyprutils libjpeg-turbo libjxl libwebp libspng
 
       - name: Build hyprgraphics with gcc
         run: |
@@ -44,7 +44,7 @@
         run: |
           sed -i 's/SigLevel    = Required DatabaseOptional/SigLevel    = 
Optional TrustAll/' /etc/pacman.conf
           pacman --noconfirm --noprogressbar -Syyu
-          pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang 
libc++ pixman cairo hyprutils libjpeg-turbo libjxl libwebp
+          pacman --noconfirm --noprogressbar -Sy gcc base-devel cmake clang 
libc++ pixman cairo hyprutils libjpeg-turbo libjxl libwebp libspng
 
       - name: Build hyprgraphics with clang
         run: |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/.github/workflows/nix.yml 
new/hyprgraphics-0.1.3/.github/workflows/nix.yml
--- old/hyprgraphics-0.1.1/.github/workflows/nix.yml    2024-12-03 
18:52:51.000000000 +0100
+++ new/hyprgraphics-0.1.3/.github/workflows/nix.yml    2025-04-06 
17:28:42.000000000 +0200
@@ -14,7 +14,6 @@
     - uses: actions/checkout@v3
 
     - uses: cachix/install-nix-action@v26
-    - uses: DeterminateSystems/magic-nix-cache-action@main
 
     # not needed (yet)
     # - uses: cachix/cachix-action@v12
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/.gitignore 
new/hyprgraphics-0.1.3/.gitignore
--- old/hyprgraphics-0.1.1/.gitignore   2024-12-03 18:52:51.000000000 +0100
+++ new/hyprgraphics-0.1.3/.gitignore   2025-04-06 17:28:42.000000000 +0200
@@ -44,3 +44,5 @@
 cmake_install.cmake
 compile_commands.json
 hyprutils.pc
+
+tests/test_output/
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/CMakeLists.txt 
new/hyprgraphics-0.1.3/CMakeLists.txt
--- old/hyprgraphics-0.1.1/CMakeLists.txt       2024-12-03 18:52:51.000000000 
+0100
+++ new/hyprgraphics-0.1.3/CMakeLists.txt       2025-04-06 17:28:42.000000000 
+0200
@@ -47,10 +47,22 @@
   hyprutils
   libjpeg
   libwebp
+  libmagic
+  spng)
+
+pkg_check_modules(
+  JXL
+  IMPORTED_TARGET
   libjxl
   libjxl_cms
   libjxl_threads
-  libmagic)
+)
+if(NOT JXL_FOUND)
+  file(GLOB_RECURSE JPEGXLFILES CONFIGURE_DEPENDS "src/*JpegXL.cpp")
+  list(REMOVE_ITEM SRCFILES ${JPEGXLFILES})
+else()
+  add_compile_definitions(JXL_FOUND)
+endif()
 
 add_library(hyprgraphics SHARED ${SRCFILES})
 target_include_directories(
@@ -60,6 +72,9 @@
 set_target_properties(hyprgraphics PROPERTIES VERSION ${HYPRGRAPHICS_VERSION}
                                               SOVERSION 0)
 target_link_libraries(hyprgraphics PkgConfig::deps)
+if(JXL_FOUND)
+  target_link_libraries(hyprgraphics PkgConfig::JXL)
+endif()
 
 # tests
 add_custom_target(tests)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/README.md 
new/hyprgraphics-0.1.3/README.md
--- old/hyprgraphics-0.1.1/README.md    2024-12-03 18:52:51.000000000 +0100
+++ new/hyprgraphics-0.1.3/README.md    2025-04-06 17:28:42.000000000 +0200
@@ -6,6 +6,22 @@
 
 Hyprgraphics depends on the ABI stability of the stdlib implementation of your 
compiler. Sover bumps will be done only for hyprgraphics ABI breaks, not stdlib.
 
+## Dependencies
+
+Requires a compiler with C++26 support.
+
+Dep list:
+ - pixman-1
+ - cairo
+ - hyprutils
+ - libjpeg
+ - libwebp
+ - libjxl [optional]
+ - libjxl_cms [optional]
+ - libjxl_threads [optional]
+ - libmagic
+ - libspng
+
 ## Building
 
 ```sh
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/VERSION 
new/hyprgraphics-0.1.3/VERSION
--- old/hyprgraphics-0.1.1/VERSION      2024-12-03 18:52:51.000000000 +0100
+++ new/hyprgraphics-0.1.3/VERSION      2025-04-06 17:28:42.000000000 +0200
@@ -1 +1 @@
-0.1.1
+0.1.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/flake.lock 
new/hyprgraphics-0.1.3/flake.lock
--- old/hyprgraphics-0.1.1/flake.lock   2024-12-03 18:52:51.000000000 +0100
+++ new/hyprgraphics-0.1.3/flake.lock   2025-04-06 17:28:42.000000000 +0200
@@ -10,11 +10,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1732288281,
-        "narHash": "sha256-XTU9B53IjGeJiJ7LstOhuxcRjCOFkQFl01H78sT9Lg4=",
+        "lastModified": 1737632363,
+        "narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=",
         "owner": "hyprwm",
         "repo": "hyprutils",
-        "rev": "b26f33cc1c8a7fd5076e19e2cce3f062dca6351c",
+        "rev": "006620eb29d54ea9086538891404c78563d1bae1",
         "type": "github"
       },
       "original": {
@@ -25,11 +25,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1732014248,
-        "narHash": "sha256-y/MEyuJ5oBWrWAic/14LaIr/u5E0wRVzyYsouYY3W6w=",
+        "lastModified": 1737469691,
+        "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "23e89b7da85c3640bbc2173fe04f4bd114342367",
+        "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab",
         "type": "github"
       },
       "original": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hyprgraphics-0.1.1/include/hyprgraphics/color/Color.hpp 
new/hyprgraphics-0.1.3/include/hyprgraphics/color/Color.hpp
--- old/hyprgraphics-0.1.1/include/hyprgraphics/color/Color.hpp 2024-12-03 
18:52:51.000000000 +0100
+++ new/hyprgraphics-0.1.3/include/hyprgraphics/color/Color.hpp 2025-04-06 
17:28:42.000000000 +0200
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <array>
 namespace Hyprgraphics {
     class CColor {
       public:
@@ -18,6 +19,25 @@
             double l = 0, a = 0, b = 0;
         };
 
+        // xy 0.0 - 1.0
+        struct xy {
+            double x = 0, y = 0;
+
+            bool   operator==(const xy& p2) const {
+                return x == p2.x && y == p2.y;
+            }
+        };
+
+        // XYZ 0.0 - 1.0
+        struct XYZ {
+            double x = 0, y = 0, z = 0;
+
+            // per-component division
+            XYZ operator/(const XYZ& other) const {
+                return {x / other.x, y / other.y, z / other.z};
+            }
+        };
+
         CColor(); // black
         CColor(const SSRGB& rgb);
         CColor(const SHSL& hsl);
@@ -27,7 +47,7 @@
         SHSL   asHSL() const;
         SOkLab asOkLab() const;
 
-        bool operator==(const CColor& other) const {
+        bool   operator==(const CColor& other) const {
             return other.r == r && other.g == g && other.b == b;
         }
 
@@ -35,4 +55,40 @@
         // SRGB space for internal color storage
         double r = 0, g = 0, b = 0;
     };
+
+    // 3x3 matrix for CM transformations
+    class CMatrix3 {
+      public:
+        CMatrix3() = default;
+        CMatrix3(const std::array<std::array<double, 3>, 3>& values);
+
+        CMatrix3                                    invert() const;
+        CColor::XYZ                                 operator*(const 
CColor::XYZ& xyz) const;
+        CMatrix3                                    operator*(const CMatrix3& 
other) const;
+
+        const std::array<std::array<double, 3>, 3>& mat();
+
+        static const CMatrix3&                      identity();
+
+      private:
+        std::array<std::array<double, 3>, 3> m = {
+            0, 0, 0, //
+            0, 0, 0, //
+            0, 0, 0, //
+        };
+    };
+
+    CColor::XYZ xy2xyz(const CColor::xy& xy);
+    CMatrix3    adaptWhite(const CColor::xy& src, const CColor::xy& dst);
+
+    struct SPCPRimaries {
+        CColor::xy red, green, blue, white;
+
+        bool       operator==(const SPCPRimaries& p2) const {
+            return red == p2.red && green == p2.green && blue == p2.blue && 
white == p2.white;
+        }
+
+        CMatrix3 toXYZ() const;                                // toXYZ() * 
rgb -> xyz
+        CMatrix3 convertMatrix(const SPCPRimaries& dst) const; // 
convertMatrix(dst) * rgb with "this" primaries -> rgb with dst primaries
+    };
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/nix/default.nix 
new/hyprgraphics-0.1.3/nix/default.nix
--- old/hyprgraphics-0.1.1/nix/default.nix      2024-12-03 18:52:51.000000000 
+0100
+++ new/hyprgraphics-0.1.3/nix/default.nix      2025-04-06 17:28:42.000000000 
+0200
@@ -9,6 +9,7 @@
   hyprutils,
   libjpeg,
   libjxl,
+  libspng,
   libwebp,
   pixman,
   version ? "git",
@@ -50,6 +51,7 @@
       hyprutils
       libjpeg
       libjxl
+      libspng
       libwebp
       pixman
     ];
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/src/color/Color.cpp 
new/hyprgraphics-0.1.3/src/color/Color.cpp
--- old/hyprgraphics-0.1.1/src/color/Color.cpp  2024-12-03 18:52:51.000000000 
+0100
+++ new/hyprgraphics-0.1.3/src/color/Color.cpp  2025-04-06 17:28:42.000000000 
+0200
@@ -1,4 +1,5 @@
 #include <hyprgraphics/color/Color.hpp>
+#include <algorithm>
 #include <cmath>
 
 using namespace Hyprgraphics;
@@ -25,6 +26,114 @@
     return p;
 }
 
+Hyprgraphics::CMatrix3::CMatrix3(const std::array<std::array<double, 3>, 3>& 
values) : m(values) {}
+
+CMatrix3 Hyprgraphics::CMatrix3::invert() const {
+    double invDet = 1 /
+        (0                                                   //
+         + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) //
+         - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) //
+         + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]) //
+        );
+
+    return CMatrix3(std::array<std::array<double, 3>, 3>{
+        (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * invDet, (m[0][2] * m[2][1] - 
m[0][1] * m[2][2]) * invDet, (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * invDet, 
//
+        (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * invDet, (m[0][0] * m[2][2] - 
m[0][2] * m[2][0]) * invDet, (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * invDet, 
//
+        (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * invDet, (m[2][0] * m[0][1] - 
m[0][0] * m[2][1]) * invDet, (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * invDet, 
//
+    });
+}
+
+CColor::XYZ Hyprgraphics::CMatrix3::operator*(const CColor::XYZ& value) const {
+    return CColor::XYZ{
+        m[0][0] * value.x + m[0][1] * value.y + m[0][2] * value.z, //
+        m[1][0] * value.x + m[1][1] * value.y + m[1][2] * value.z, //
+        m[2][0] * value.x + m[2][1] * value.y + m[2][2] * value.z, //
+    };
+}
+
+CMatrix3 Hyprgraphics::CMatrix3::operator*(const CMatrix3& other) const {
+    std::array<std::array<double, 3>, 3> res = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+    for (int i = 0; i < 3; i++) {
+        for (int j = 0; j < 3; j++) {
+            for (int k = 0; k < 3; k++) {
+                res[i][j] += m[i][k] * other.m[k][j];
+            }
+        }
+    }
+    return CMatrix3(res);
+}
+
+const std::array<std::array<double, 3>, 3>& Hyprgraphics::CMatrix3::mat() {
+    return m;
+};
+
+const CMatrix3& CMatrix3::identity() {
+    static const CMatrix3 Identity3 = CMatrix3(std::array<std::array<double, 
3>, 3>{
+        1, 0, 0, //
+        0, 1, 0, //
+        0, 0, 1, //
+    });
+    return Identity3;
+}
+
+CColor::XYZ Hyprgraphics::xy2xyz(const CColor::xy& xy) {
+    if (xy.y == 0.0)
+        return {0.0, 0.0, 0.0};
+
+    return {xy.x / xy.y, 1.0, (1.0 - xy.x - xy.y) / xy.y};
+}
+
+CMatrix3 Bradford = CMatrix3(std::array<std::array<double, 3>, 3>{
+    0.8951, 0.2664, -0.1614, //
+    -0.7502, 1.7135, 0.0367, //
+    0.0389, -0.0685, 1.0296, //
+});
+
+CMatrix3 BradfordInv = Bradford.invert();
+
+CMatrix3 Hyprgraphics::adaptWhite(const CColor::xy& src, const CColor::xy& 
dst) {
+    if (src == dst)
+        return CMatrix3::identity();
+
+    const auto srcXYZ  = xy2xyz(src);
+    const auto dstXYZ  = xy2xyz(dst);
+    const auto factors = (Bradford * dstXYZ) / (Bradford * srcXYZ);
+
+    return BradfordInv *
+        CMatrix3(std::array<std::array<double, 3>, 3>{
+            factors.x, 0.0, 0.0, //
+            0.0, factors.y, 0.0, //
+            0.0, 0.0, factors.z, //
+        }) *
+        Bradford;
+}
+
+CMatrix3 Hyprgraphics::SPCPRimaries::toXYZ() const {
+    const auto r = xy2xyz(red);
+    const auto g = xy2xyz(green);
+    const auto b = xy2xyz(blue);
+    const auto w = xy2xyz(white);
+
+    const auto invMat = CMatrix3(std::array<std::array<double, 3>, 3>{
+                                     r.x, g.x, b.x, //
+                                     r.y, g.y, b.y, //
+                                     r.z, g.z, b.z, //
+                                 })
+                            .invert();
+
+    const auto s = invMat * w;
+
+    return std::array<std::array<double, 3>, 3>{
+        s.x * r.x, s.y * g.x, s.z * b.x, //
+        s.x * r.y, s.y * g.y, s.z * b.y, //
+        s.x * r.z, s.y * g.z, s.z * b.z, //
+    };
+}
+
+CMatrix3 Hyprgraphics::SPCPRimaries::convertMatrix(const SPCPRimaries& dst) 
const {
+    return dst.toXYZ().invert() * adaptWhite(white, dst.white) * toXYZ();
+}
+
 Hyprgraphics::CColor::CColor() {
     ;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/src/image/Image.cpp 
new/hyprgraphics-0.1.3/src/image/Image.cpp
--- old/hyprgraphics-0.1.1/src/image/Image.cpp  2024-12-03 18:52:51.000000000 
+0100
+++ new/hyprgraphics-0.1.3/src/image/Image.cpp  2025-04-06 17:28:42.000000000 
+0200
@@ -1,8 +1,11 @@
 #include <hyprgraphics/image/Image.hpp>
 #include "formats/Bmp.hpp"
 #include "formats/Jpeg.hpp"
+#ifdef JXL_FOUND
 #include "formats/JpegXL.hpp"
+#endif
 #include "formats/Webp.hpp"
+#include "formats/Png.hpp"
 #include <magic.h>
 #include <format>
 
@@ -13,41 +16,48 @@
     std::expected<cairo_surface_t*, std::string> CAIROSURFACE;
     const auto                                   len = path.length();
     if (path.find(".png") == len - 4 || path.find(".PNG") == len - 4) {
-        CAIROSURFACE = cairo_image_surface_create_from_png(path.c_str());
-        mime = "image/png";
+        CAIROSURFACE = PNG::createSurfaceFromPNG(path);
+        mime         = "image/png";
     } else if (path.find(".jpg") == len - 4 || path.find(".JPG") == len - 4 || 
path.find(".jpeg") == len - 5 || path.find(".JPEG") == len - 5) {
         CAIROSURFACE  = JPEG::createSurfaceFromJPEG(path);
         imageHasAlpha = false;
-        mime = "image/jpeg";
+        mime          = "image/jpeg";
     } else if (path.find(".bmp") == len - 4 || path.find(".BMP") == len - 4) {
         CAIROSURFACE  = BMP::createSurfaceFromBMP(path);
         imageHasAlpha = false;
-        mime = "image/bmp";
+        mime          = "image/bmp";
     } else if (path.find(".webp") == len - 5 || path.find(".WEBP") == len - 5) 
{
         CAIROSURFACE = WEBP::createSurfaceFromWEBP(path);
-        mime = "image/webp";
+        mime         = "image/webp";
     } else if (path.find(".jxl") == len - 4 || path.find(".JXL") == len - 4) {
+
+#ifdef JXL_FOUND
         CAIROSURFACE = JXL::createSurfaceFromJXL(path);
-        mime = "image/jxl";
+        mime         = "image/jxl";
+#else
+        lastError = "hyprgraphics compiled without JXL support";
+        return;
+#endif
+
     } else {
         // magic is slow, so only use it when no recognized extension is found
-        auto handle = magic_open(MAGIC_NONE | MAGIC_COMPRESS);
+        auto handle = magic_open(MAGIC_NONE | MAGIC_COMPRESS | MAGIC_SYMLINK);
         magic_load(handle, nullptr);
 
         const auto type_str   = std::string(magic_file(handle, path.c_str()));
         const auto first_word = type_str.substr(0, type_str.find(" "));
 
         if (first_word == "PNG") {
-            CAIROSURFACE = cairo_image_surface_create_from_png(path.c_str());
-            mime = "image/png";
+            CAIROSURFACE = PNG::createSurfaceFromPNG(path);
+            mime         = "image/png";
         } else if (first_word == "JPEG") {
             CAIROSURFACE  = JPEG::createSurfaceFromJPEG(path);
             imageHasAlpha = false;
-            mime = "image/jpeg";
+            mime          = "image/jpeg";
         } else if (first_word == "BMP") {
             CAIROSURFACE  = BMP::createSurfaceFromBMP(path);
             imageHasAlpha = false;
-            mime = "image/bmp";
+            mime          = "image/bmp";
         } else {
             lastError = "unrecognized image";
             return;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/src/image/formats/Bmp.cpp 
new/hyprgraphics-0.1.3/src/image/formats/Bmp.cpp
--- old/hyprgraphics-0.1.1/src/image/formats/Bmp.cpp    2024-12-03 
18:52:51.000000000 +0100
+++ new/hyprgraphics-0.1.3/src/image/formats/Bmp.cpp    2025-04-06 
17:28:42.000000000 +0200
@@ -102,8 +102,8 @@
     if (!std::filesystem::exists(path))
         return std::unexpected("loading bmp: file doesn't exist");
 
-    std::ifstream  bitmapImageStream(path);
-    BmpHeader      bitmapHeader;
+    std::ifstream bitmapImageStream(path);
+    BmpHeader     bitmapHeader;
     if (const auto RET = bitmapHeader.load(bitmapImageStream); RET.has_value())
         return std::unexpected("loading bmp: " + *RET);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/src/image/formats/Png.cpp 
new/hyprgraphics-0.1.3/src/image/formats/Png.cpp
--- old/hyprgraphics-0.1.1/src/image/formats/Png.cpp    1970-01-01 
01:00:00.000000000 +0100
+++ new/hyprgraphics-0.1.3/src/image/formats/Png.cpp    2025-04-06 
17:28:42.000000000 +0200
@@ -0,0 +1,93 @@
+#include "Png.hpp"
+#include <spng.h>
+#include <vector>
+#include <fstream>
+#include <filesystem>
+#include <cstdint>
+#include <hyprutils/utils/ScopeGuard.hpp>
+using namespace Hyprutils::Utils;
+
+static std::vector<unsigned char> readBinaryFile(const std::string& filename) {
+    std::ifstream f(filename, std::ios::binary);
+    if (!f.good())
+        return {};
+    f.unsetf(std::ios::skipws);
+    return {std::istreambuf_iterator<char>(f), 
std::istreambuf_iterator<char>()};
+}
+
+std::expected<cairo_surface_t*, std::string> PNG::createSurfaceFromPNG(const 
std::string& path) {
+    if (!std::filesystem::exists(path))
+        return std::unexpected("loading png: file doesn't exist");
+
+    spng_ctx*   ctx = spng_ctx_new(0);
+
+    CScopeGuard x([&] { spng_ctx_free(ctx); });
+
+    const auto  PNGCONTENT = readBinaryFile(path);
+
+    if (PNGCONTENT.empty())
+        return std::unexpected("loading png: file content was empty (bad 
file?)");
+
+    spng_set_png_buffer(ctx, PNGCONTENT.data(), PNGCONTENT.size());
+
+    spng_ihdr ihdr{0};
+    if (int ret = spng_get_ihdr(ctx, &ihdr); ret)
+        return std::unexpected(std::string{"loading png: spng_get_ihdr failed: 
"} + spng_strerror(ret));
+
+    int fmt = SPNG_FMT_PNG;
+    if (ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
+        fmt = SPNG_FMT_RGB8;
+
+    size_t imageLength = 0;
+    if (int ret = spng_decoded_image_size(ctx, fmt, &imageLength); ret)
+        return std::unexpected(std::string{"loading png: 
spng_decoded_image_size failed: "} + spng_strerror(ret));
+
+    uint8_t* imageData = (uint8_t*)malloc(imageLength);
+
+    if (!imageData)
+        return std::unexpected("loading png: mallocing failed, out of 
memory?");
+
+    // TODO: allow proper decode of high bitrate images
+    bool succeededDecode = false;
+    int  ret             = spng_decode_image(ctx, imageData, imageLength, 
SPNG_FMT_RGBA8, 0);
+    if (!ret)
+        succeededDecode = true;
+
+    if (!succeededDecode && ret == SPNG_EBUFSIZ) {
+        // hack, but I don't know why decoded_image_size is sometimes wrong
+        imageLength = ihdr.height * ihdr.width * 4 /* FIXME: this is wrong if 
we doing >32bpp!!!! */;
+        imageData   = (uint8_t*)realloc(imageData, imageLength);
+
+        ret = spng_decode_image(ctx, imageData, imageLength, SPNG_FMT_RGBA8, 
0);
+    }
+
+    if (!ret)
+        succeededDecode = true;
+
+    if (!succeededDecode) {
+        free(imageData);
+        return std::unexpected(std::string{"loading png: spng_decode_image 
failed: "} + spng_strerror(ret) + " (bad image?)");
+    }
+
+    // convert RGBA8888 -> ARGB8888 premult for cairo
+    for (size_t i = 0; i < imageLength; i += 4) {
+        uint8_t r, g, b, a;
+        a = ((*((uint32_t*)(imageData + i))) & 0xFF000000) >> 24;
+        b = ((*((uint32_t*)(imageData + i))) & 0x00FF0000) >> 16;
+        g = ((*((uint32_t*)(imageData + i))) & 0x0000FF00) >> 8;
+        r = (*((uint32_t*)(imageData + i))) & 0x000000FF;
+
+        r *= ((float)a / 255.F);
+        g *= ((float)a / 255.F);
+        b *= ((float)a / 255.F);
+
+        *((uint32_t*)(imageData + i)) = (((uint32_t)a) << 24) | (((uint32_t)r) 
<< 16) | (((uint32_t)g) << 8) | (uint32_t)b;
+    }
+
+    auto CAIROSURFACE = cairo_image_surface_create_for_data(imageData, 
CAIRO_FORMAT_ARGB32, ihdr.width, ihdr.height, ihdr.width * 4);
+
+    if (!CAIROSURFACE)
+        return std::unexpected("loading png: cairo failed");
+
+    return CAIROSURFACE;
+}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/src/image/formats/Png.hpp 
new/hyprgraphics-0.1.3/src/image/formats/Png.hpp
--- old/hyprgraphics-0.1.1/src/image/formats/Png.hpp    1970-01-01 
01:00:00.000000000 +0100
+++ new/hyprgraphics-0.1.3/src/image/formats/Png.hpp    2025-04-06 
17:28:42.000000000 +0200
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <cairo/cairo.h>
+#include <string>
+#include <expected>
+
+namespace PNG {
+    std::expected<cairo_surface_t*, std::string> createSurfaceFromPNG(const 
std::string&);
+};
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/hyprgraphics-0.1.1/tests/image.cpp 
new/hyprgraphics-0.1.3/tests/image.cpp
--- old/hyprgraphics-0.1.1/tests/image.cpp      2024-12-03 18:52:51.000000000 
+0100
+++ new/hyprgraphics-0.1.3/tests/image.cpp      2025-04-06 17:28:42.000000000 
+0200
@@ -16,7 +16,16 @@
 
     std::println("Loaded {} successfully: Image is {}x{} of type {}", path, 
image.cairoSurface()->size().x, image.cairoSurface()->size().y, 
image.getMime());
 
-    return true;
+    const auto TEST_DIR = std::filesystem::current_path().string() + 
"/test_output";
+
+    // try to write it for inspection
+    if (!std::filesystem::exists(TEST_DIR))
+        std::filesystem::create_directory(TEST_DIR);
+
+    std::string name = image.getMime();
+    std::replace(name.begin(), name.end(), '/', '_');
+
+    return cairo_surface_write_to_png(image.cairoSurface()->cairo(), (TEST_DIR 
+ "/" + name + ".png").c_str()) == CAIRO_STATUS_SUCCESS;
 }
 
 int main(int argc, char** argv, char** envp) {
@@ -25,8 +34,12 @@
     for (auto& file : 
std::filesystem::directory_iterator("./resource/images/")) {
         if (!file.is_regular_file())
             continue;
-
-        EXPECT(tryLoadImage(file.path()), true);
+        auto expectation = true;
+#ifndef JXL_FOUND
+        if (file.path().filename() == "hyprland.jxl")
+            expectation = false;
+#endif
+        EXPECT(tryLoadImage(file.path()), expectation);
     }
 
     return ret;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/hyprgraphics-0.1.1/tests/resource/images/hyprland.symlink 
new/hyprgraphics-0.1.3/tests/resource/images/hyprland.symlink
--- old/hyprgraphics-0.1.1/tests/resource/images/hyprland.symlink       
1970-01-01 01:00:00.000000000 +0100
+++ new/hyprgraphics-0.1.3/tests/resource/images/hyprland.symlink       
2025-06-05 20:37:25.785003556 +0200
@@ -0,0 +1 @@
+symbolic link to hyprland.png

Reply via email to