Skip to content

Commit

Permalink
core: Bitmap image support (#175)
Browse files Browse the repository at this point in the history
* Add handler "reload" to do a change of wallpaper by one hyprctl execution

* fixed contain parameter handling in "handleReload"

* added bitmap (.bmp) image support

* refactored

* reserve -> resize
  • Loading branch information
barrrguzin authored Jun 7, 2024
1 parent 2c57525 commit 374d6e2
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 0 deletions.
126 changes: 126 additions & 0 deletions src/helpers/Bmp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include "Bmp.hpp"

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

class BmpHeader {
public:
unsigned char format[2];
uint32_t sizeOfFile;
uint16_t reserved1;
uint16_t reserved2;
uint32_t dataOffset;
uint32_t sizeOfBitmapHeader;
uint32_t width;
uint32_t height;
uint16_t numberOfColors;
uint16_t numberOfBitPerPixel;
uint32_t compressionMethod;
uint32_t imageSize;
uint32_t horizontalResolutionPPM;
uint32_t verticalResolutionPPM;
uint32_t numberOfCollors;
uint32_t numberOfImportantCollors;

BmpHeader(std::ifstream& file) {
file.seekg(0, std::ios::end);
uint32_t streamLength = file.tellg();
file.seekg(0, std::ios::beg);

file.read(reinterpret_cast<char*>(&format), sizeof(format));
if (!(format[0] == 66 && format[1] == 77)) {
Debug::log(ERR, "Unable to parse bitmap header: wrong bmp file type");
exit(1);
}

file.read(reinterpret_cast<char*>(&sizeOfFile), sizeof(sizeOfFile));

if (sizeOfFile != streamLength) {
Debug::log(ERR, "Unable to parse bitmap header: wrong value of file size header");
exit(1);
}

file.read(reinterpret_cast<char*>(&reserved1), sizeof(reserved1));
file.read(reinterpret_cast<char*>(&reserved2), sizeof(reserved2));
file.read(reinterpret_cast<char*>(&dataOffset), sizeof(dataOffset));
file.read(reinterpret_cast<char*>(&sizeOfBitmapHeader), sizeof(sizeOfBitmapHeader));
file.read(reinterpret_cast<char*>(&width), sizeof(width));
file.read(reinterpret_cast<char*>(&height), sizeof(height));
file.read(reinterpret_cast<char*>(&numberOfColors), sizeof(numberOfColors));
file.read(reinterpret_cast<char*>(&numberOfBitPerPixel), sizeof(numberOfBitPerPixel));
file.read(reinterpret_cast<char*>(&compressionMethod), sizeof(compressionMethod));
file.read(reinterpret_cast<char*>(&imageSize), sizeof(imageSize));
file.read(reinterpret_cast<char*>(&horizontalResolutionPPM), sizeof(horizontalResolutionPPM));
file.read(reinterpret_cast<char*>(&verticalResolutionPPM), sizeof(verticalResolutionPPM));
file.read(reinterpret_cast<char*>(&numberOfCollors), sizeof(numberOfCollors));
file.read(reinterpret_cast<char*>(&numberOfImportantCollors), sizeof(numberOfImportantCollors));

if (!imageSize)
imageSize = sizeOfFile - dataOffset;

if (imageSize != (width * height * numberOfBitPerPixel/8)) {
Debug::log(ERR, "Unable to parse bitmap header: wrong image size");
exit(1);
}

file.seekg(dataOffset);
};
};

void reflectImage(unsigned char* image, uint32_t numberOfRows, int stride) {
int rowStart = 0;
int rowEnd = numberOfRows - 1;
std::vector<unsigned char> temp;
temp.resize(stride);
while (rowStart < rowEnd) {
memcpy(&temp[0], &image[rowStart * stride], stride);
memcpy(&image[rowStart * stride], &image[rowEnd * stride], stride);
memcpy(&image[rowEnd * stride], &temp[0], stride);
rowStart++;
rowEnd--;
}
};

void convertRgbToArgb(std::ifstream& imageStream, unsigned char* outputImage, uint32_t newImageSize) {
uint8_t forthBitCounter = 0;
unsigned long imgCursor = 0;
while (imgCursor < newImageSize) {
imageStream.read(reinterpret_cast<char*>(&outputImage[imgCursor]), 1);
imgCursor++;
forthBitCounter++;
if (forthBitCounter == 3) {
outputImage[imgCursor] = 0;
imgCursor++;
forthBitCounter = 0;
}
}
};

cairo_surface_t* BMP::createSurfaceFromBMP(const std::string& path) {

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

std::ifstream bitmapImageStream(path);
BmpHeader bitmapHeader(bitmapImageStream);

cairo_format_t format = CAIRO_FORMAT_ARGB32;
int stride = cairo_format_stride_for_width (format, bitmapHeader.width);
unsigned char* imageData = (unsigned char*) malloc(bitmapHeader.height * stride);

if (bitmapHeader.numberOfBitPerPixel == 24)
convertRgbToArgb(bitmapImageStream, imageData, bitmapHeader.height * stride);
else if (bitmapHeader.numberOfBitPerPixel == 32)
bitmapImageStream.read(reinterpret_cast<char*>(&imageData), bitmapHeader.imageSize);
else {
Debug::log(ERR, "createSurfaceFromBMP: unsupported bmp format");
bitmapImageStream.close();
exit(1);
}
bitmapImageStream.close();
reflectImage(imageData, bitmapHeader.height, stride);
return cairo_image_surface_create_for_data(imageData, format, bitmapHeader.width, bitmapHeader.height, stride);
}
7 changes: 7 additions & 0 deletions src/helpers/Bmp.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "../defines.hpp"

namespace BMP {
cairo_surface_t* createSurfaceFromBMP(const std::string&);
};
6 changes: 6 additions & 0 deletions src/render/WallpaperTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ 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(".bmp") == len - 4 || path.find(".BMP") == len - 4) {
CAIROSURFACE = BMP::createSurfaceFromBMP(path);
m_bHasAlpha = false;
} else if (path.find(".webp") == len - 5 || path.find(".WEBP") == len - 5) {
CAIROSURFACE = WEBP::createSurfaceFromWEBP(path);
} else {
Expand All @@ -33,6 +36,9 @@ void CWallpaperTarget::create(const std::string& path) {
} else if (first_word == "JPEG") {
CAIROSURFACE = JPEG::createSurfaceFromJPEG(path);
m_bHasAlpha = false;
} else if (first_word == "BMP") {
CAIROSURFACE = BMP::createSurfaceFromBMP(path);
m_bHasAlpha = false;
} else {
Debug::log(CRIT, "unrecognized image %s", path.c_str());
exit(1);
Expand Down
1 change: 1 addition & 0 deletions src/render/WallpaperTarget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

class CWallpaperTarget {
Expand Down

0 comments on commit 374d6e2

Please sign in to comment.