From 7b87336d453f54041c7e27aaac7e37fb5f2cf4b2 Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Mon, 4 Jul 2022 12:51:15 +0200 Subject: [PATCH] added jpeg support --- README.md | 6 +-- src/helpers/Jpeg.cpp | 75 ++++++++++++++++++++++++++++++++++ src/helpers/Jpeg.hpp | 8 ++++ src/render/WallpaperTarget.cpp | 5 +-- src/render/WallpaperTarget.hpp | 5 ++- 5 files changed, 90 insertions(+), 9 deletions(-) create mode 100644 src/helpers/Jpeg.cpp create mode 100644 src/helpers/Jpeg.hpp diff --git a/README.md b/README.md index ecad31b..a48d240 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,4 @@ You can use `hyprctl hyprpaper` (if on Hyprland) to issue a keyword, for example hyprctl hyprpaper wallpaper DP-1,~/Pictures/myepicpng.png ``` -For other compositors, the socket works like socket1 of Hyprland, and is located in `/tmp/hypr/.hyprpaper.sock` (this path only when Hyprland is not running!) - -# todos - -- jpeg support +For other compositors, the socket works like socket1 of Hyprland, and is located in `/tmp/hypr/.hyprpaper.sock` (this path only when Hyprland is not running!) \ No newline at end of file diff --git a/src/helpers/Jpeg.cpp b/src/helpers/Jpeg.cpp new file mode 100644 index 0000000..c1423ae --- /dev/null +++ b/src/helpers/Jpeg.cpp @@ -0,0 +1,75 @@ +#include "Jpeg.hpp" + +#include +#include +#include + +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +#error "your system is not little endian, jpeg will not work, ping vaxry or something" +#endif + +cairo_surface_t* JPEG::createSurfaceFromJPEG(const std::string& path) { + + if (!std::filesystem::exists(path)) { + Debug::log(ERR, "createSurfaceFromJPEG: file doesn't exist??"); + exit(1); + } + + if (__BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__) { + Debug::log(CRIT, "tried to load a jpeg on a big endian system! ping vaxry he is lazy."); + 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 JPEG is in the memory + + jpeg_decompress_struct decompressStruct; + jpeg_error_mgr errorManager; + + decompressStruct.err = jpeg_std_error(&errorManager); + jpeg_create_decompress(&decompressStruct); + jpeg_mem_src(&decompressStruct, (const unsigned char*)imageRawData, fileInfo.st_size); + jpeg_read_header(&decompressStruct, true); + + decompressStruct.out_color_space = JCS_EXT_BGRA; + + // decompress + jpeg_start_decompress(&decompressStruct); + + auto cairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, decompressStruct.output_width, decompressStruct.output_height); + + if (cairo_surface_status(cairoSurface) != CAIRO_STATUS_SUCCESS) { + Debug::log(ERR, "createSurfaceFromJPEG: Cairo Failed (?)"); + exit(1); + } + + const auto CAIRODATA = cairo_image_surface_get_data(cairoSurface); + const auto CAIROSTRIDE = cairo_image_surface_get_stride(cairoSurface); + JSAMPROW rowRead; + + while (decompressStruct.output_scanline < decompressStruct.output_height) { + const auto PROW = CAIRODATA + (decompressStruct.output_scanline * CAIROSTRIDE); + rowRead = PROW; + jpeg_read_scanlines(&decompressStruct, &rowRead, 1); + } + + cairo_surface_mark_dirty(cairoSurface); + cairo_surface_set_mime_data(cairoSurface, CAIRO_MIME_TYPE_JPEG, (const unsigned char*)imageRawData, fileInfo.st_size, free, imageRawData); + jpeg_finish_decompress(&decompressStruct); + jpeg_destroy_decompress(&decompressStruct); + + return cairoSurface; +} \ No newline at end of file diff --git a/src/helpers/Jpeg.hpp b/src/helpers/Jpeg.hpp new file mode 100644 index 0000000..b217ec0 --- /dev/null +++ b/src/helpers/Jpeg.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../defines.hpp" +#include + +namespace JPEG { + cairo_surface_t* createSurfaceFromJPEG(const std::string&); +}; \ No newline at end of file diff --git a/src/render/WallpaperTarget.cpp b/src/render/WallpaperTarget.cpp index e7f21c2..8079d07 100644 --- a/src/render/WallpaperTarget.cpp +++ b/src/render/WallpaperTarget.cpp @@ -9,9 +9,8 @@ void CWallpaperTarget::create(const std::string& path) { if (path.find(".png") == path.length() - 4) { CAIROSURFACE = cairo_image_surface_create_from_png(path.c_str()); } else if (path.find(".jpg") == path.length() - 4 || path.find(".jpeg") == path.length() - 5) { - Debug::log(ERR, ".jpg images are not yet supported! :("); - exit(1); - return; + CAIROSURFACE = JPEG::createSurfaceFromJPEG(path); + m_bHasAlpha = false; } else { Debug::log(CRIT, "unrecognized image %s", path.c_str()); exit(1); diff --git a/src/render/WallpaperTarget.hpp b/src/render/WallpaperTarget.hpp index 767d890..85f8fe4 100644 --- a/src/render/WallpaperTarget.hpp +++ b/src/render/WallpaperTarget.hpp @@ -1,6 +1,7 @@ #pragma once #include "../defines.hpp" +#include "../helpers/Jpeg.hpp" class CWallpaperTarget { public: @@ -10,7 +11,9 @@ public: std::string m_szPath; - Vector2D m_vSize; + Vector2D m_vSize; + + bool m_bHasAlpha = true; cairo_surface_t* m_pCairoSurface; }; \ No newline at end of file