Compare commits
2 Commits
90483c9dcd
...
7a3d59e03e
Author | SHA1 | Date | |
---|---|---|---|
7a3d59e03e | |||
d37dd56496 |
@@ -1,24 +1,28 @@
|
||||
# Minimum CMake version required, we'll just use the latest version.
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
# 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)
|
||||
|
||||
# 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_package(DPP REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
|
||||
pkg_check_modules(CAIRO REQUIRED cairo)
|
||||
|
||||
# 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.
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR}
|
||||
${SQLITE3_INCLUDE_DIR})
|
||||
target_include_directories(
|
||||
${PROJECT_NAME} PRIVATE ${DPP_INCLUDE_DIR} ${SQLITE3_INCLUDE_DIR}
|
||||
${CAIRO_INCLUDE_DIR})
|
||||
|
||||
# Set C++ version
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 20
|
||||
|
BIN
assets/report_bumper.png
Normal file
BIN
assets/report_bumper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@@ -27,7 +27,7 @@ void createCommands(const dpp::ready_t &event, dpp::cluster &bot) {
|
||||
dpp::slashcommand(COMMAND_GENERATE_REPORT,
|
||||
COMMAND_GENERATE_REPORT_DESCRIPTION, bot.me.id)
|
||||
.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))
|
||||
.add_option(dpp::command_option(
|
||||
dpp::command_option_type::co_string, "headline",
|
||||
|
@@ -1,10 +1,46 @@
|
||||
#include "../Common.hpp"
|
||||
#include "../Utility/CairoTools.hpp"
|
||||
|
||||
#include <dpp/dispatcher.h>
|
||||
#include <dpp/dpp.h>
|
||||
#include <dpp/guild.h>
|
||||
#include <dpp/message.h>
|
||||
#include <dpp/misc-enum.h>
|
||||
#include <dpp/queues.h>
|
||||
#include <dpp/snowflake.h>
|
||||
#include <dpp/user.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
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
|
||||
//
|
||||
|
80
src/Utility/CairoGenerate.cpp
Normal file
80
src/Utility/CairoGenerate.cpp
Normal 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;
|
||||
}
|
39
src/Utility/CairoTools.cpp
Normal file
39
src/Utility/CairoTools.cpp
Normal 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);
|
||||
}
|
31
src/Utility/CairoTools.hpp
Normal file
31
src/Utility/CairoTools.hpp
Normal 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
3
src/Utility/Utility.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
// Unity Build
|
||||
#include "CairoGenerate.cpp"
|
||||
#include "CairoTools.cpp"
|
Reference in New Issue
Block a user