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.
|
# 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
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,
|
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",
|
||||||
|
@@ -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
|
||||||
|
//
|
||||||
|
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