Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitmap image support #175

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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));
barrrguzin marked this conversation as resolved.
Show resolved Hide resolved

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
Loading