#include // for operator""s, chrono_literals #include // for sleep_for #include #include #include "panel.hpp" #include "color.hpp" #include "render.hpp" #include "dbc.hpp" #include #include #include #include #include #include #include using namespace std::chrono_literals; using namespace fmt; using std::string, std::cout, std::vector; struct HSVColor { unsigned long h = 0; unsigned long s = 0; unsigned long v = 0; }; struct RGBColor { unsigned long r = 0; unsigned long g = 0; unsigned long b = 0; }; // taken from https://github.com/python/cpython/blob/3.9/Lib/colorsys.py#L140 HSVColor rgb_to_hsv(sf::Color rgb) { float r = rgb.r / 255.0f; float g = rgb.g / 255.0f; float b = rgb.b / 255.0f; float maxc = std::max({rgb.r, rgb.g, rgb.b}); float minc = std::min({rgb.r, rgb.g, rgb.b}); float v = maxc; // if minc == maxc: if(minc == maxc) { // no hue no sat, so gray with value return {0, 0, uint8_t(v * 255.0)}; } float s = (maxc - minc) / maxc; float rc = (maxc - r) / (maxc - minc); float gc = (maxc - g) / (maxc - minc); float bc = (maxc - b) / (maxc - minc); float h = 0.0f; if(r == maxc) { h = bc-gc; } else if(g == maxc) { h = 2.0 + rc - bc; } else { h = 4.0 + gc - rc; h = std::fmod((h/6.0), 1.0); } return {uint8_t(h * 255.0f), uint8_t(s * 255.0f), uint8_t(v * 255.0f)}; } int main(int argc, char *argv[]) { ftxui::Terminal::SetColorSupport(ftxui::Terminal::Color::TrueColor); _setmode(_fileno(stdout), _O_U16TEXT); dbc::check(argc == 2, "USAGE: img2ansi "); string image_file(argv[1]); println("LOADING IMAGE: {}", image_file); // load the image from argv sf::Image image; image.loadFromFile(image_file); // divide the image into cells auto size = image.getSize(); const int cell = 3; // create a grid panel to hold the cells Panel panel(0, 0, 0, 0, true); println("IMAGE SIZE {},{}", size.x, size.y); RGBColor avg{0,0,0}; typedef vector ColorRow; vector colors(size.x / cell, ColorRow(size.y / cell)); // LOL, so bad but just the start for(unsigned int i = 0; i < size.x / cell; i++) { for(unsigned int j = 0; j < size.y / cell; j++) { // sum the cell for(unsigned int x = 0; x < cell ; x++) { for(unsigned int y = 0; y < cell ; y++) { auto pixel = image.getPixel((i*cell) + x, (j * cell) + y); avg.r += pixel.r; avg.g += pixel.g; avg.b += pixel.b; } } // average it for the cell size RGBColor color = {avg.r / (cell * cell), avg.g / (cell * cell), avg.b / (cell * cell)}; // add it colors[i][j] = color; // reset avg = {0,0,0}; } } Canvas drawing; SFMLRender renderer; if(renderer.resize_grid(10, panel)) { println("RESIZED: {},{}", panel.width, panel.height); // set canvas to best size drawing = Canvas(panel.width * 2, panel.height * 4); } panel.set_renderer(Renderer([&]{ for(size_t x = 0; x < colors.size(); x++) { for(size_t y = 0; y < colors[0].size(); y++) { auto color = colors[x][y]; ftxui::Color block = ftxui::Color::RGB(color.r, color.g, color.b); drawing.DrawText(x * 2, y * 4, "█", block); } } return ftxui::canvas(drawing); })); sf::Event event; while(renderer.is_open()) { renderer.draw(panel); renderer.display(); while(renderer.poll_event(event)) { if(event.type == sf::Event::Closed) { renderer.close(); } } std::this_thread::sleep_for(10ms); } return 0; }