Skip to content

Commit

Permalink
feat: Add webp support (#113)
Browse files Browse the repository at this point in the history
* feat: add webp support

* readme: add libwebp dependency

* refactor: move including webp to source file

* style: fix using tab

* style: make const value upper-case

* Nix: add libwebp

---------

Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
  • Loading branch information
tobiichi3227 and fufexan authored Dec 21, 2023
1 parent a5e21e2 commit ae4f498
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 8 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.4)
project(hyprpaper
project(hyprpaper
DESCRIPTION "A blazing fast wayland wallpaper utility"
)

Expand Down Expand Up @@ -41,7 +41,7 @@ add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-m
find_package(Threads REQUIRED)

find_package(PkgConfig REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols cairo pango pangocairo libjpeg)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-client wayland-protocols cairo pango pangocairo libjpeg libwebp)

file(GLOB_RECURSE SRCFILES "src/*.cpp")

Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The development files of these packages need to be installed on the system for `
- libglvnd
- libglvnd-core
- libjpeg-turbo
- libwebp

Also `gcc-c++` and `ninja` needs to installed.

Expand Down Expand Up @@ -67,7 +68,7 @@ wallpaper = monitor2,/path/to/next_image.png
# .. more monitors
```

Preload will tell Hyprland to load a particular image (supported formats: png, jpg, jpeg). 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 for a wildcard (aka fallback). 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, 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 for a wildcard (aka fallback). You can also use `desc:` followed by the monitor's description without the (PORT) at the end)

You may add `contain:` before the file path in `wallpaper=` to set the mode to contain instead of cover:

Expand Down Expand Up @@ -106,9 +107,9 @@ In the actual configuration for Hyprland, *hyprland.conf*, variables can be set

*~/.config/hypr/hyprland.conf*
```
$w1 = hyprctl hyprpaper wallpaper "DP-1,~/Pictures/myepicpng.png"
$w2 = hyprctl hyprpaper wallpaper "DP-1,~/Pictures/myepicpngToo.png"
$w3 = hyprctl hyprpaper wallpaper "DP-1,~/Pictures/myepicpngAlso.png"
$w1 = hyprctl hyprpaper wallpaper "DP-1,~/Pictures/myepicpng.png"
$w2 = hyprctl hyprpaper wallpaper "DP-1,~/Pictures/myepicpngToo.png"
$w3 = hyprctl hyprpaper wallpaper "DP-1,~/Pictures/myepicpngAlso.png"
#yes use quotes around desired monitor and wallpaper
#... continued with desired amount
```
Expand All @@ -127,7 +128,7 @@ bind=SUPER,2,exec,$w2 #SuperKey + 2 switches to wallpaper $w2 on DP-1 as def
bind=SUPER,3,workspace,3 #Superkey + 3 switches to workspace 3
bind=SUPER,3,exec,$w3 #SuperKey + 3 switches to wallpaper $w3 on DP-1 as defined in the variable
#... and so on
#... and so on
```
Because the default behavior in Hyprland is to also switch the workspace whenever movetoworkspace is used to move a window to another workspace you may want to include the following:

Expand Down
2 changes: 2 additions & 0 deletions nix/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
libselinux,
libsepol,
libthai,
libwebp,
pango,
pcre,
util-linux,
Expand Down Expand Up @@ -44,6 +45,7 @@ stdenv.mkDerivation {
libselinux
libsepol
libthai
libwebp
pango
pcre
wayland
Expand Down
84 changes: 84 additions & 0 deletions src/helpers/Webp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include "Webp.hpp"

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <webp/decode.h>

cairo_surface_t* WEBP::createSurfaceFromWEBP(const std::string& path) {

if (!std::filesystem::exists(path)) {
Debug::log(ERR, "createSurfaceFromWEBP: file doesn't exist??");
exit(1);
}

void* imageRawData;

struct stat fileInfo = {};

const auto FD = open(path.c_str(), O_RDONLY);

fstat(FD, &fileInfo);

imageRawData = malloc(fileInfo.st_size);

read(FD, imageRawData, fileInfo.st_size);

close(FD);

// now the WebP is in the memory

WebPDecoderConfig config;
if (!WebPInitDecoderConfig(&config)) {
Debug::log(CRIT, "WebPInitDecoderConfig Failed");
exit(1);
}

if (WebPGetFeatures((const unsigned char*)imageRawData, fileInfo.st_size, &config.input) != VP8_STATUS_OK) {
Debug::log(ERR, "createSurfaceFromWEBP: file is not webp format");
free(imageRawData);
exit(1);
}

const auto HEIGHT = config.input.height;
const auto WIDTH = config.input.width;

auto cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
if (cairo_surface_status(cairoSurface) != CAIRO_STATUS_SUCCESS) {
Debug::log(CRIT, "createSurfaceFromWEBP: Cairo Failed (?)");
cairo_surface_destroy(cairoSurface);
exit(1);
}


if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
config.output.colorspace = MODE_bgrA;
else
config.output.colorspace = MODE_Argb;


const auto CAIRODATA = cairo_image_surface_get_data(cairoSurface);
const auto CAIROSTRIDE = cairo_image_surface_get_stride(cairoSurface);

config.options.no_fancy_upsampling = 1;
config.output.u.RGBA.rgba = CAIRODATA;
config.output.u.RGBA.stride = CAIROSTRIDE;
config.output.u.RGBA.size = CAIROSTRIDE * HEIGHT;
config.output.is_external_memory = 1;
config.output.width = WIDTH;
config.output.height = HEIGHT;

if (WebPDecode((const unsigned char*)imageRawData, fileInfo.st_size, &config) != VP8_STATUS_OK) {
Debug::log(CRIT, "createSurfaceFromWEBP: WebP Decode Failed (?)");
exit(1);
}

cairo_surface_mark_dirty(cairoSurface);
cairo_surface_set_mime_data(cairoSurface, CAIRO_MIME_TYPE_PNG, (const unsigned char*)imageRawData, fileInfo.st_size, free, imageRawData);

WebPFreeDecBuffer(&config.output);

return cairoSurface;

}
7 changes: 7 additions & 0 deletions src/helpers/Webp.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "../defines.hpp"

namespace WEBP {
cairo_surface_t* createSurfaceFromWEBP(const std::string&);
};
2 changes: 2 additions & 0 deletions src/render/WallpaperTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ void CWallpaperTarget::create(const std::string& path) {
} 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);
m_bHasAlpha = false;
} else if (path.find(".webp") == len - 5 || path.find(".WEBP") == len - 5) {
CAIROSURFACE = WEBP::createSurfaceFromWEBP(path);
} else {
// magic is slow, so only use it when no recognized extension is found
auto handle = magic_open(MAGIC_NONE|MAGIC_COMPRESS);
Expand Down
3 changes: 2 additions & 1 deletion src/render/WallpaperTarget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

#include "../defines.hpp"
#include "../helpers/Jpeg.hpp"
#include "../helpers/Webp.hpp"

class CWallpaperTarget {
public:

~CWallpaperTarget();

void create(const std::string& path);

std::string m_szPath;
Expand Down

0 comments on commit ae4f498

Please sign in to comment.