mirror of
https://github.com/hyprwm/hyprlock.git
synced 2024-11-16 23:05:58 +01:00
Added BMP image handling, the same as in hyprpaper
This commit is contained in:
parent
cf0e975fed
commit
80718cf048
3 changed files with 142 additions and 0 deletions
122
src/helpers/Bmp.cpp
Normal file
122
src/helpers/Bmp.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include "Bmp.hpp"
|
||||
|
||||
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::filesystem::path& 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);
|
||||
}
|
15
src/helpers/Bmp.hpp
Normal file
15
src/helpers/Bmp.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "string.h"
|
||||
#include <vector>
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace BMP {
|
||||
cairo_surface_t* createSurfaceFromBMP(const std::filesystem::path&);
|
||||
};
|
|
@ -12,6 +12,7 @@
|
|||
#include "../helpers/Webp.hpp"
|
||||
#include "src/helpers/Color.hpp"
|
||||
#include "src/helpers/Log.hpp"
|
||||
#include <src/helpers/Bmp.hpp>
|
||||
|
||||
CAsyncResourceGatherer::CAsyncResourceGatherer() {
|
||||
if (g_pHyprlock->getScreencopy())
|
||||
|
@ -85,6 +86,7 @@ SPreloadedAsset* CAsyncResourceGatherer::getAssetByID(const std::string& id) {
|
|||
}
|
||||
|
||||
enum class FileType {
|
||||
BMP,
|
||||
PNG,
|
||||
JPEG,
|
||||
WEBP,
|
||||
|
@ -104,6 +106,8 @@ FileType getFileType(const std::filesystem::path& path) {
|
|||
ft = FileType::JPEG;
|
||||
else if (ext == ".webp")
|
||||
ft = FileType::WEBP;
|
||||
else if (ext == ".bmp")
|
||||
ft = FileType::BMP;
|
||||
else {
|
||||
// magic is slow, so only use it when no recognized extension is found
|
||||
auto handle = magic_open(MAGIC_NONE | MAGIC_COMPRESS);
|
||||
|
@ -130,6 +134,7 @@ cairo_surface_t* getCairoSurfaceFromImageFile(const std::filesystem::path& path)
|
|||
case FileType::PNG: cairoSurface = cairo_image_surface_create_from_png(path.c_str()); break;
|
||||
case FileType::JPEG: cairoSurface = JPEG::createSurfaceFromJPEG(path); break;
|
||||
case FileType::WEBP: cairoSurface = WEBP::createSurfaceFromWEBP(path); break;
|
||||
case FileType::BMP: cairoSurface = BMP::createSurfaceFromBMP(path); break;
|
||||
default: Debug::log(ERR, "unrecognized image format of {}", path.c_str());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue