From e873f7bb6c444c3b3b4a5cb674e0156a5af44dc1 Mon Sep 17 00:00:00 2001 From: Toni500git Date: Sun, 15 Sep 2024 20:59:30 +0200 Subject: [PATCH] experimental: add image as logo in terminal it's uncomplete and just a prototype. right now only to be used with kitty --- include/config.hpp | 1 + src/display.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++--- src/main.cpp | 13 +++++++-- 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index a11bec0..e02b948 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -65,6 +65,7 @@ class Config // inner management std::string m_custom_distro; + std::string m_image_backend; bool m_disable_source = false; bool m_display_distro = true; bool m_print_logo_only = false; diff --git a/src/display.cpp b/src/display.cpp index a0d252d..eb15041 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -2,6 +2,9 @@ #include "display.hpp" +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + #include #include #include @@ -40,6 +43,56 @@ std::string Display::detect_distro(const Config& config) } } +static std::vector render_with_image(const Config& config, const colors_t& colors) +{ + std::string path{ Display::detect_distro(config) }; + systemInfo_t systemInfo{}; + std::vector layout{ config.layout }; + + int image_width, image_height, channels; + + // load the image and get its width and height + unsigned char* img = stbi_load(config.source_path.c_str(), &image_width, &image_height, &channels, 0); + + if (img) + stbi_image_free(img); + else + die("Unable to load image '{}'", config.source_path); + + if (!config.ascii_logo_type.empty()) + { + const size_t& pos = path.rfind('.'); + + if (pos != std::string::npos) + path.insert(pos, "_" + config.ascii_logo_type); + else + path += "_" + config.ascii_logo_type; + } + + // this is just for parse() to auto add the distro colors + std::ifstream file(path, std::ios::binary); + std::string line, _; + + while (std::getline(file, line)) + parse(line, systemInfo, _, config, colors, false); + + for (std::string& layout : layout) + layout = parse(layout, systemInfo, _, config, colors, true); + + // erase each element for each instance of MAGIC_LINE + layout.erase(std::remove_if(layout.begin(), layout.end(), + [](const std::string_view str) { return str.find(MAGIC_LINE) != std::string::npos; }), + layout.end()); + + for (size_t i = 0; i < layout.size(); i++) + { + for (size_t _ = 0; _ < config.offset; _++) // I use _ because we don't need it + layout.at(i).insert(0, " "); + } + + return layout; +} + std::vector Display::render(const Config& config, const colors_t& colors, const bool already_analyzed_file, const std::string_view path) { @@ -52,7 +105,7 @@ std::vector Display::render(const Config& config, const colors_t& c die("You need to specify if either using a custom distro ascii art OR a custom source path"); } - debug("path = {}", path); + debug("Display::render path = {}", path); std::ifstream file; std::ifstream fileToAnalyze; // both have same path @@ -67,6 +120,8 @@ std::vector Display::render(const Config& config, const colors_t& c std::string line; std::vector pureAsciiArtLens; int maxLineLength = -1; + std::string image_backend_cmd; + // first check if the file is an image // without even using the same library that "file" uses @@ -74,12 +129,20 @@ std::vector Display::render(const Config& config, const colors_t& c if (!already_analyzed_file) { debug("Display::render() analyzing file"); - std::array buffer; + std::array buffer; fileToAnalyze.read(reinterpret_cast(&buffer.at(0)), buffer.size()); if (is_file_image(buffer.data())) - die("The source file '{}' is a binary file.\n" + { + if (config.m_image_backend == "kitty") + { + image_backend_cmd = fmt::format("kitty +kitten icat --align left {}", path); + } + shell_exec(image_backend_cmd); + return render_with_image(config, colors); + } + /* die("The source file '{}' is a binary file.\n" "Please currently use the GUI mode for rendering the image/gif (use -h for more details)", - path); + path);*/ } for (int i = 0; i < config.logo_padding_top; i++) @@ -188,6 +251,7 @@ std::vector Display::render(const Config& config, const colors_t& c } return layout; + } void Display::display(const std::vector& renderResult) diff --git a/src/main.cpp b/src/main.cpp index c7a7df3..22c9884 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -260,9 +260,8 @@ static bool parseargs(int argc, char* argv[], Config& config, const std::string_ int opt = 0; int option_index = 0; opterr = 1; // re-enable since before we disabled for "invalid option" error - const char *optstring = "-VhnLlga::f:o:C:d:D:s:"; - static const struct option opts[] = - { + const char *optstring = "-VhnLlga::f:o:C:i:d:D:s:"; + static const struct option opts[] = { {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"no-display", no_argument, 0, 'n'}, @@ -277,6 +276,9 @@ static bool parseargs(int argc, char* argv[], Config& config, const std::string_ {"distro", required_argument, 0, 'd'}, {"source-path", required_argument, 0, 's'}, + {"image-backend", required_argument, 0, 'i'}, + {"kitty", no_argument, 0, "kitty"_fnv1a16}, + {"sep-reset", required_argument, 0, "sep-reset"_fnv1a16}, {"title-sep", required_argument, 0, "title-sep"_fnv1a16}, {"sep-reset-after", optional_argument, 0, "sep-reset-after"_fnv1a16}, @@ -325,6 +327,8 @@ static bool parseargs(int argc, char* argv[], Config& config, const std::string_ config.m_custom_distro = str_tolower(optarg); break; case 's': config.source_path = optarg; break; + case 'i': + config.m_image_backend = optarg; break; case 'a': if (OPTIONAL_ARGUMENT_IS_PRESENT) config.ascii_logo_type = optarg; @@ -379,6 +383,9 @@ static bool parseargs(int argc, char* argv[], Config& config, const std::string_ config.sep_reset_after = true; break; + case "kitty"_fnv1a16: + config.m_image_backend = "kitty"; break; + default: return false; }