Added support for jpeg(stb) and webp(libwebp)

This commit is contained in:
2025-07-23 03:33:25 +03:00
parent 7a3d59e03e
commit efa80c4c87
5 changed files with 88 additions and 13 deletions

View File

@@ -14,15 +14,16 @@ find_package(DPP REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
pkg_check_modules(CAIRO REQUIRED cairo)
pkg_check_modules(WEBP REQUIRED libwebpdecoder)
# Link the pre-installed DPP package.
target_link_libraries(${PROJECT_NAME} ${DPP_LIBRARIES} ${SQLITE3_LIBRARIES}
${CAIRO_LIBRARIES})
${CAIRO_LIBRARIES} ${WEBP_LIBRARIES})
# Include the DPP directories.
target_include_directories(
${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR} ${SQLITE3_INCLUDE_DIR}
${CAIRO_INCLUDE_DIR})
${CAIRO_INCLUDE_DIR} ${WEBP_INCLUDE_DIR})
# Set C++ version
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20

View File

@@ -1,6 +1,8 @@
#include "../Common.hpp"
#include "../Utility/CairoTools.hpp"
#include <algorithm>
#include <cctype>
#include <dpp/dispatcher.h>
#include <dpp/dpp.h>
#include <dpp/guild.h>
@@ -25,11 +27,22 @@ void commandGenerateReport(const dpp::slashcommand_t &event,
bot.request(
file.url, dpp::http_method::m_get,
[event, &bot, fileType](const dpp::http_request_completion_t &result) {
std::string responseData = GenerateReportImage(
fileType->second(
result.body), // Image itself processed for cario to handle
std::get<std::string>(event.get_parameter("headline")));
auto imageAsSurface = fileType->second(result.body);
if (imageAsSurface == nullptr) {
event.edit_response("Failed to load the background image :(");
return;
}
// Don't forget that its only funny if it is all in upper case
std::string headline =
std::get<std::string>(event.get_parameter("headline"));
// Never seen this method before but looks awesome
std::transform(headline.begin(), headline.end(), headline.data(),
::toupper);
std::string responseData =
GenerateReportImage(imageAsSurface, headline);
dpp::message response(event.command.channel_id, "");
response.add_file("report.png", responseData);
event.edit_response(response);

View File

@@ -1,4 +1,5 @@
#include "CairoTools.hpp"
#include <cctype>
std::string GenerateReportImage(cairo_surface_t *background,
std::string headline) {

View File

@@ -1,5 +1,11 @@
#include "CairoTools.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
#include <webp/decode.h>
#include <webp/types.h>
std::unordered_map<std::string,
std::function<cairo_surface_t *(const std::string &)>>
supportedImageFileTypes{{"image/png", pngToCairoSurface},
@@ -31,9 +37,63 @@ cairo_surface_t *pngToCairoSurface(const std::string &data) {
return cairo_image_surface_create_from_png_stream(
cairoReadPNGdata, const_cast<std::string *>(&data));
}
cairo_surface_t *jpegToCairoSurface(std::string data) {
return cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 200);
///
/// JPEG and WEBP
///
inline cairo_surface_t *swizzleToBGRA(unsigned char *data, int width,
int height, bool isjpeg = true) {
// AI code start - Reviewed, looks solid
cairo_surface_t *surface =
cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
unsigned char *surface_data = cairo_image_surface_get_data(surface);
int stride = cairo_image_surface_get_stride(surface);
// Convert RGB to BGRA
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned char *src =
data + (y * width + x) * (isjpeg ? 3 : 4); // Swizzling
unsigned char *dst = surface_data + y * stride + x * 4; // Still swizzling
dst[0] = src[2]; // B
dst[1] = src[1]; // G
dst[2] = src[0]; // R
dst[3] = src[3]; // A
}
cairo_surface_t *webpToCairoSurface(std::string data) {
return cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 200);
}
cairo_surface_mark_dirty(surface);
// AI code end
return surface;
}
cairo_surface_t *jpegToCairoSurface(const std::string &data) {
int width, height, channels;
unsigned char *imgData = stbi_load_from_memory(
reinterpret_cast<const unsigned char *>(data.data()), data.size(), &width,
&height, &channels, 3 // Channel count
);
if (imgData == nullptr) {
return nullptr;
}
auto image = swizzleToBGRA(imgData, width, height);
stbi_image_free(imgData);
return image;
}
cairo_surface_t *webpToCairoSurface(const std::string &data) {
int width, height;
unsigned char *imgData =
WebPDecodeRGBA(reinterpret_cast<const uint8_t *>(data.data()),
data.size(), &width, &height);
if (imgData == nullptr) {
return nullptr;
}
auto image = swizzleToBGRA(imgData, width, height, false);
WebPFree(imgData);
return image;
}

View File

@@ -6,7 +6,7 @@
#define REPORT_HEIGHT 1200
#define REPORT_HEIGHT_OFFSET 200
#define REPORT_TEXT_START_X 40
#define REPORT_TEXT_JUMP_Y 120
#define REPORT_TEXT_JUMP_Y 125
#define REPORT_TEXT_FONT_SIZE 120.0
#define REPORT_TEXT_LENGTH 26
#define REPORT_RESOURCE_BUMPER_PATH "./assets/report_bumper.png"
@@ -23,8 +23,8 @@ cairo_status_t cairoOutputAsPNGStream(void *closure, const unsigned char *data,
unsigned int length);
cairo_surface_t *pngToCairoSurface(const std::string &data);
cairo_surface_t *jpegToCairoSurface(std::string data);
cairo_surface_t *webpToCairoSurface(std::string data);
cairo_surface_t *jpegToCairoSurface(const std::string &data);
cairo_surface_t *webpToCairoSurface(const std::string &data);
extern std::unordered_map<std::string,
std::function<cairo_surface_t *(const std::string &)>>