Compare commits

..

2 Commits

8 changed files with 200 additions and 7 deletions

View File

@@ -1,24 +1,28 @@
# Minimum CMake version required, we'll just use the latest version. # Minimum CMake version required, we'll just use the latest version.
cmake_minimum_required(VERSION 3.22) cmake_minimum_required(VERSION 3.22)
# Project name, version and description # Project name, version and description
project(TheBartender VERSION 1.0) project(TheBartender VERSION 0.3)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
# Create an executable # Create an executable
add_executable(${PROJECT_NAME} src/Base/Entry.cpp src/Commands.cpp) add_executable(${PROJECT_NAME} src/Base/Entry.cpp src/Commands.cpp
src/Utility/Utility.cpp)
# Find our pre-installed DPP package (using FindDPP.cmake). # Find our pre-installed DPP package (using FindDPP.cmake).
find_package(DPP REQUIRED) find_package(DPP REQUIRED)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(SQLITE3 REQUIRED sqlite3) pkg_check_modules(SQLITE3 REQUIRED sqlite3)
pkg_check_modules(CAIRO REQUIRED cairo)
# Link the pre-installed DPP package. # Link the pre-installed DPP package.
target_link_libraries(${PROJECT_NAME} ${DPP_LIBRARIES} ${SQLITE3_LIBRARIES}) target_link_libraries(${PROJECT_NAME} ${DPP_LIBRARIES} ${SQLITE3_LIBRARIES}
${CAIRO_LIBRARIES})
# Include the DPP directories. # Include the DPP directories.
target_include_directories(${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR} target_include_directories(
${SQLITE3_INCLUDE_DIR}) ${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR} ${SQLITE3_INCLUDE_DIR}
${CAIRO_INCLUDE_DIR})
# Set C++ version # Set C++ version
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20 set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20

BIN
assets/report_bumper.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -27,7 +27,7 @@ void createCommands(const dpp::ready_t &event, dpp::cluster &bot) {
dpp::slashcommand(COMMAND_GENERATE_REPORT, dpp::slashcommand(COMMAND_GENERATE_REPORT,
COMMAND_GENERATE_REPORT_DESCRIPTION, bot.me.id) COMMAND_GENERATE_REPORT_DESCRIPTION, bot.me.id)
.add_option(dpp::command_option( .add_option(dpp::command_option(
dpp::command_option_type::co_attachment, "background-image", dpp::command_option_type::co_attachment, "image",
COMMAND_GENERATE_REPORT_ARGS_IMAGE_DESCRIPTION, true)) COMMAND_GENERATE_REPORT_ARGS_IMAGE_DESCRIPTION, true))
.add_option(dpp::command_option( .add_option(dpp::command_option(
dpp::command_option_type::co_string, "headline", dpp::command_option_type::co_string, "headline",

View File

@@ -1,10 +1,46 @@
#include "../Common.hpp" #include "../Common.hpp"
#include "../Utility/CairoTools.hpp"
#include <dpp/dispatcher.h> #include <dpp/dispatcher.h>
#include <dpp/dpp.h> #include <dpp/dpp.h>
#include <dpp/guild.h> #include <dpp/guild.h>
#include <dpp/message.h>
#include <dpp/misc-enum.h>
#include <dpp/queues.h>
#include <dpp/snowflake.h> #include <dpp/snowflake.h>
#include <dpp/user.h> #include <dpp/user.h>
#include <functional>
#include <string>
#include <unordered_map>
void commandGenerateReport(const dpp::slashcommand_t &event, void commandGenerateReport(const dpp::slashcommand_t &event,
dpp::cluster &bot) {} dpp::cluster &bot) {
event.thinking();
dpp::snowflake fileId =
std::get<dpp::snowflake>(event.get_parameter("image"));
dpp::attachment file = event.command.get_resolved_attachment(fileId);
auto fileType = supportedImageFileTypes.find(file.content_type);
if (fileType != supportedImageFileTypes.end()) {
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")));
dpp::message response(event.command.channel_id, "");
response.add_file("report.png", responseData);
event.edit_response(response);
});
} else {
event.edit_response(
"File type: " + file.content_type +
" is not allowed. Only PNG, JPEG, and WEBP are allowed!");
}
}
//
// ACTUAL GENERATION STARTS HERE
//

View File

@@ -0,0 +1,80 @@
#include "CairoTools.hpp"
std::string GenerateReportImage(cairo_surface_t *background,
std::string headline) {
cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, REPORT_WIDTH, REPORT_HEIGHT);
cairo_t *ctx = cairo_create(surface);
cairo_set_source_rgb(ctx, 0, 0, 0);
cairo_paint(ctx);
int imgW = 0, imgH = 0;
// Background Image
cairo_save(ctx);
imgW = cairo_image_surface_get_width(background);
imgH = cairo_image_surface_get_height(background);
cairo_scale(ctx, (double)REPORT_WIDTH / imgW,
(double)(REPORT_HEIGHT - REPORT_HEIGHT_OFFSET) / imgH);
cairo_set_source_surface(ctx, background, 0, 0);
cairo_paint(ctx);
cairo_restore(ctx);
// Gradient
cairo_pattern_t *gradient =
cairo_pattern_create_linear(0, 0, 0, REPORT_HEIGHT);
cairo_pattern_add_color_stop_rgba(gradient, 0.85, 0, 0, 0, 1);
cairo_pattern_add_color_stop_rgba(gradient, 0, 0, 0, 0, 0);
cairo_rectangle(ctx, 0, 0, REPORT_WIDTH, REPORT_HEIGHT);
cairo_set_source(ctx, gradient);
cairo_fill(ctx);
// Bumper
cairo_save(ctx);
cairo_surface_t *bumper =
cairo_image_surface_create_from_png(REPORT_RESOURCE_BUMPER_PATH);
imgW = cairo_image_surface_get_width(bumper);
imgH = cairo_image_surface_get_height(bumper);
cairo_scale(ctx, (double)REPORT_WIDTH / imgW, 1.5);
cairo_set_source_surface(ctx, bumper, 0, REPORT_HEIGHT - (imgH * 7.1));
cairo_paint(ctx);
cairo_restore(ctx);
// Text
cairo_select_font_face(ctx, "Steelfish", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(ctx, REPORT_TEXT_FONT_SIZE);
// Iteration 3
std::stringstream text(headline + " ");
std::string output, part;
std::vector<std::string> outputList;
while (text.tellp() == std::streampos(0)) {
std::getline(text, part, ' ');
if (output.length() + part.length() < REPORT_TEXT_LENGTH) {
output += part + ' ';
continue;
}
outputList.push_back(output);
output = part + ' ';
}
outputList.push_back(output);
// Display Text
int lineCount = 0;
for (std::string line : outputList) {
cairo_move_to(ctx, REPORT_TEXT_START_X,
REPORT_HEIGHT -
(REPORT_TEXT_JUMP_Y * (outputList.size() - lineCount++)));
cairo_set_source_rgb(ctx, CAIRO_TEXT_WHITE);
cairo_show_text(ctx, line.c_str());
}
std::string data;
cairo_surface_write_to_png_stream(surface, cairoOutputAsPNGStream, &data);
return data;
}

View File

@@ -0,0 +1,39 @@
#include "CairoTools.hpp"
std::unordered_map<std::string,
std::function<cairo_surface_t *(const std::string &)>>
supportedImageFileTypes{{"image/png", pngToCairoSurface},
{"image/jpeg", jpegToCairoSurface},
{"image/webp", webpToCairoSurface}};
cairo_status_t cairoReadPNGdata(void *closure, unsigned char *data,
unsigned int length) {
std::string *imageData = static_cast<std::string *>(closure);
static size_t offset = 0;
if (offset + length > imageData->size()) {
return CAIRO_STATUS_READ_ERROR;
}
memcpy(data, imageData->data() + offset, length);
offset += length;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t cairoOutputAsPNGStream(void *closure, const unsigned char *data,
unsigned int length) {
std::string *output = static_cast<std::string *>(closure);
output->append(reinterpret_cast<const char *>(data), length);
return CAIRO_STATUS_SUCCESS;
}
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);
}
cairo_surface_t *webpToCairoSurface(std::string data) {
return cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 200);
}

View File

@@ -0,0 +1,31 @@
#include <cairo/cairo.h>
#include <dpp/dpp.h>
#include <string>
#define REPORT_WIDTH 1000
#define REPORT_HEIGHT 1200
#define REPORT_HEIGHT_OFFSET 200
#define REPORT_TEXT_START_X 40
#define REPORT_TEXT_JUMP_Y 120
#define REPORT_TEXT_FONT_SIZE 120.0
#define REPORT_TEXT_LENGTH 26
#define REPORT_RESOURCE_BUMPER_PATH "./assets/report_bumper.png"
#define CAIRO_TEXT_WHITE 0.87, 0.87, 0.87
std::string GenerateReportImage(cairo_surface_t *background,
std::string headline);
// File type management
cairo_status_t cairoReadPNGdata(void *closure, unsigned char *data,
unsigned int length);
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);
extern std::unordered_map<std::string,
std::function<cairo_surface_t *(const std::string &)>>
supportedImageFileTypes;

3
src/Utility/Utility.cpp Normal file
View File

@@ -0,0 +1,3 @@
// Unity Build
#include "CairoGenerate.cpp"
#include "CairoTools.cpp"