Skip to content

Commit

Permalink
experimental: add image as logo in terminal
Browse files Browse the repository at this point in the history
it's uncomplete and just a prototype. right now only to be used with kitty
  • Loading branch information
Toni500github committed Sep 15, 2024
1 parent b2f2887 commit e873f7b
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 7 deletions.
1 change: 1 addition & 0 deletions include/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
72 changes: 68 additions & 4 deletions src/display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#include "display.hpp"

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#include <algorithm>
#include <array>
#include <filesystem>
Expand Down Expand Up @@ -40,6 +43,56 @@ std::string Display::detect_distro(const Config& config)
}
}

static std::vector<std::string> render_with_image(const Config& config, const colors_t& colors)
{
std::string path{ Display::detect_distro(config) };
systemInfo_t systemInfo{};
std::vector<std::string> 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<std::string> Display::render(const Config& config, const colors_t& colors, const bool already_analyzed_file,
const std::string_view path)
{
Expand All @@ -52,7 +105,7 @@ std::vector<std::string> 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
Expand All @@ -67,19 +120,29 @@ std::vector<std::string> Display::render(const Config& config, const colors_t& c
std::string line;
std::vector<size_t> 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
// No extra bloatware nice
if (!already_analyzed_file)
{
debug("Display::render() analyzing file");
std::array<unsigned char, 16> buffer;
std::array<unsigned char, 32> buffer;
fileToAnalyze.read(reinterpret_cast<char*>(&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++)
Expand Down Expand Up @@ -188,6 +251,7 @@ std::vector<std::string> Display::render(const Config& config, const colors_t& c
}

return layout;

}

void Display::display(const std::vector<std::string>& renderResult)
Expand Down
13 changes: 10 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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'},
Expand All @@ -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},
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit e873f7b

Please sign in to comment.