mirror of
https://github.com/hyprwm/hyprpaper.git
synced 2024-12-22 12:19:49 +01:00
core: Add support for JPEG-XL (#212)
This commit is contained in:
parent
3f8cc92109
commit
dbea6cdf0c
7 changed files with 126 additions and 3 deletions
|
@ -60,6 +60,9 @@ pkg_check_modules(
|
||||||
pangocairo
|
pangocairo
|
||||||
libjpeg
|
libjpeg
|
||||||
libwebp
|
libwebp
|
||||||
|
libjxl
|
||||||
|
libjxl_cms
|
||||||
|
libjxl_threads
|
||||||
hyprlang>=0.2.0
|
hyprlang>=0.2.0
|
||||||
hyprutils>=0.2.0)
|
hyprutils>=0.2.0)
|
||||||
|
|
||||||
|
|
|
@ -29,18 +29,19 @@ The development files of these packages need to be installed on the system for `
|
||||||
- libglvnd-core
|
- libglvnd-core
|
||||||
- libjpeg-turbo
|
- libjpeg-turbo
|
||||||
- libwebp
|
- libwebp
|
||||||
|
- libjxl
|
||||||
- hyprlang
|
- hyprlang
|
||||||
- hyprutils
|
- hyprutils
|
||||||
- hyprwayland-scanner
|
- hyprwayland-scanner
|
||||||
|
|
||||||
To install all of these in Fedora, run this command:
|
To install all of these in Fedora, run this command:
|
||||||
```
|
```
|
||||||
sudo dnf install wayland-devel wayland-protocols-devel hyprlang-devel pango-devel cairo-devel file-devel libglvnd-devel libglvnd-core-devel libjpeg-turbo-devel libwebp-devel gcc-c++ hyprutils-devel hyprwayland-scanner
|
sudo dnf install wayland-devel wayland-protocols-devel hyprlang-devel pango-devel cairo-devel file-devel libglvnd-devel libglvnd-core-devel libjpeg-turbo-devel libwebp-devel libjxl-devel gcc-c++ hyprutils-devel hyprwayland-scanner
|
||||||
```
|
```
|
||||||
|
|
||||||
On Arch:
|
On Arch:
|
||||||
```
|
```
|
||||||
sudo pacman -S ninja gcc wayland-protocols libjpeg-turbo libwebp pango cairo pkgconf cmake libglvnd wayland hyprutils hyprwayland-scanner hyprlang
|
sudo pacman -S ninja gcc wayland-protocols libjpeg-turbo libwebp libjxl pango cairo pkgconf cmake libglvnd wayland hyprutils hyprwayland-scanner hyprlang
|
||||||
```
|
```
|
||||||
|
|
||||||
On OpenSUSE:
|
On OpenSUSE:
|
||||||
|
@ -89,7 +90,7 @@ splash = true
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Preload will tell Hyprland to load a particular image (supported formats: png, jpg, jpeg, webp). Wallpaper will apply the wallpaper to the selected output (`monitor` is the monitor's name, easily can be retrieved with `hyprctl monitors`. You can leave it empty to set all monitors without an active wallpaper. You can also use `desc:` followed by the monitor's description without the (PORT) at the end)
|
Preload will tell Hyprland to load a particular image (supported formats: png, jpg, jpeg, jpeg xl, webp). Wallpaper will apply the wallpaper to the selected output (`monitor` is the monitor's name, easily can be retrieved with `hyprctl monitors`. You can leave it empty to set all monitors without an active wallpaper. You can also use `desc:` followed by the monitor's description without the (PORT) at the end)
|
||||||
|
|
||||||
You may add `contain:` or `tile:` before the file path in `wallpaper=` to set the mode to either contain or tile, respectively, instead of cover:
|
You may add `contain:` or `tile:` before the file path in `wallpaper=` to set the mode to either contain or tile, respectively, instead of cover:
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
libdatrie,
|
libdatrie,
|
||||||
libGL,
|
libGL,
|
||||||
libjpeg,
|
libjpeg,
|
||||||
|
libjxl,
|
||||||
libselinux,
|
libselinux,
|
||||||
libsepol,
|
libsepol,
|
||||||
libthai,
|
libthai,
|
||||||
|
@ -66,6 +67,7 @@ stdenv.mkDerivation {
|
||||||
libdatrie
|
libdatrie
|
||||||
libGL
|
libGL
|
||||||
libjpeg
|
libjpeg
|
||||||
|
libjxl
|
||||||
libselinux
|
libselinux
|
||||||
libsepol
|
libsepol
|
||||||
libthai
|
libthai
|
||||||
|
|
107
src/helpers/JpegXL.cpp
Normal file
107
src/helpers/JpegXL.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#include "JpegXL.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <jxl/decode_cxx.h>
|
||||||
|
#include <jxl/resizable_parallel_runner_cxx.h>
|
||||||
|
|
||||||
|
cairo_surface_t* JXL::createSurfaceFromJXL(const std::string& path) {
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(path)) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: file doesn't exist??");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream file(path, std::ios::binary | std::ios::ate);
|
||||||
|
file.exceptions(std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);
|
||||||
|
std::vector<uint8_t> bytes(file.tellg());
|
||||||
|
file.seekg(0);
|
||||||
|
file.read(reinterpret_cast<char*>(bytes.data()), bytes.size());
|
||||||
|
|
||||||
|
JxlSignature signature = JxlSignatureCheck(bytes.data(), bytes.size());
|
||||||
|
if (signature != JXL_SIG_CODESTREAM && signature != JXL_SIG_CONTAINER) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: file is not JXL format");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dec = JxlDecoderMake(nullptr);
|
||||||
|
auto runner = JxlResizableParallelRunnerMake(nullptr);
|
||||||
|
if (JXL_DEC_SUCCESS != JxlDecoderSetParallelRunner(dec.get(), JxlResizableParallelRunner, runner.get())) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: JxlDecoderSetParallelRunner failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE)) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: JxlDecoderSubscribeEvents failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
JxlDecoderSetInput(dec.get(), bytes.data(), bytes.size());
|
||||||
|
JxlDecoderCloseInput(dec.get());
|
||||||
|
if (JXL_DEC_BASIC_INFO != JxlDecoderProcessInput(dec.get())) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: JxlDecoderProcessInput failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
JxlBasicInfo basicInfo;
|
||||||
|
if (JXL_DEC_SUCCESS != JxlDecoderGetBasicInfo(dec.get(), &basicInfo)) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: JxlDecoderGetBasicInfo failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, basicInfo.xsize, basicInfo.ysize);
|
||||||
|
if (cairo_surface_status(cairoSurface) != CAIRO_STATUS_SUCCESS) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: Cairo Failed (?)");
|
||||||
|
cairo_surface_destroy(cairoSurface);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto CAIRODATA = cairo_image_surface_get_data(cairoSurface);
|
||||||
|
|
||||||
|
JxlPixelFormat format = {
|
||||||
|
.num_channels = 4,
|
||||||
|
.data_type = JXL_TYPE_UINT8,
|
||||||
|
.endianness = JXL_LITTLE_ENDIAN,
|
||||||
|
.align = cairo_image_surface_get_stride(cairoSurface),
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto OUTPUTSIZE = basicInfo.xsize * basicInfo.ysize * format.num_channels;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
JxlDecoderStatus status = JxlDecoderProcessInput(dec.get());
|
||||||
|
if (status == JXL_DEC_ERROR) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: JxlDecoderProcessInput failed");
|
||||||
|
cairo_surface_destroy(cairoSurface);
|
||||||
|
exit(1);
|
||||||
|
} else if (status == JXL_DEC_NEED_MORE_INPUT) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: JxlDecoderProcessInput expected more input");
|
||||||
|
cairo_surface_destroy(cairoSurface);
|
||||||
|
exit(1);
|
||||||
|
} else if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
|
||||||
|
JxlResizableParallelRunnerSetThreads(runner.get(), JxlResizableParallelRunnerSuggestThreads(basicInfo.xsize, basicInfo.ysize));
|
||||||
|
size_t bufferSize;
|
||||||
|
if (JXL_DEC_SUCCESS != JxlDecoderImageOutBufferSize(dec.get(), &format, &bufferSize)) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: JxlDecoderImageOutBufferSize failed");
|
||||||
|
cairo_surface_destroy(cairoSurface);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (bufferSize != OUTPUTSIZE) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: invalid output buffer size");
|
||||||
|
cairo_surface_destroy(cairoSurface);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format, CAIRODATA, bufferSize)) {
|
||||||
|
Debug::log(ERR, "createSurfaceFromJXL: JxlDecoderSetImageOutBuffer failed");
|
||||||
|
cairo_surface_destroy(cairoSurface);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else if (status == JXL_DEC_FULL_IMAGE) {
|
||||||
|
for (size_t i = 0; i < OUTPUTSIZE - 2; i += format.num_channels) {
|
||||||
|
std::swap(CAIRODATA[i + 0], CAIRODATA[i + 2]);
|
||||||
|
}
|
||||||
|
cairo_surface_mark_dirty(cairoSurface);
|
||||||
|
cairo_surface_set_mime_data(cairoSurface, "image/jxl", bytes.data(), bytes.size(), nullptr, nullptr);
|
||||||
|
return cairoSurface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
src/helpers/JpegXL.hpp
Normal file
7
src/helpers/JpegXL.hpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../defines.hpp"
|
||||||
|
|
||||||
|
namespace JXL {
|
||||||
|
cairo_surface_t* createSurfaceFromJXL(const std::string&);
|
||||||
|
};
|
|
@ -24,6 +24,8 @@ void CWallpaperTarget::create(const std::string& path) {
|
||||||
m_bHasAlpha = false;
|
m_bHasAlpha = false;
|
||||||
} else if (path.find(".webp") == len - 5 || path.find(".WEBP") == len - 5) {
|
} else if (path.find(".webp") == len - 5 || path.find(".WEBP") == len - 5) {
|
||||||
CAIROSURFACE = WEBP::createSurfaceFromWEBP(path);
|
CAIROSURFACE = WEBP::createSurfaceFromWEBP(path);
|
||||||
|
} else if (path.find(".jxl") == len - 4 || path.find(".JXL") == len - 4) {
|
||||||
|
CAIROSURFACE = JXL::createSurfaceFromJXL(path);
|
||||||
} else {
|
} else {
|
||||||
// magic is slow, so only use it when no recognized extension is found
|
// 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);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../helpers/Jpeg.hpp"
|
#include "../helpers/Jpeg.hpp"
|
||||||
#include "../helpers/Bmp.hpp"
|
#include "../helpers/Bmp.hpp"
|
||||||
#include "../helpers/Webp.hpp"
|
#include "../helpers/Webp.hpp"
|
||||||
|
#include "../helpers/JpegXL.hpp"
|
||||||
|
|
||||||
class CWallpaperTarget {
|
class CWallpaperTarget {
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue