You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.2 KiB
181 lines
4.2 KiB
#include <chrono> // for operator""s, chrono_literals
|
|
#include <thread> // for sleep_for
|
|
#include <fmt/core.h>
|
|
#include <filesystem>
|
|
#include "panel.hpp"
|
|
#include "color.hpp"
|
|
#include "render.hpp"
|
|
#include "dbc.hpp"
|
|
#include <SFML/Graphics/Image.hpp>
|
|
#include <ftxui/screen/color.hpp>
|
|
#include <ftxui/screen/terminal.hpp>
|
|
#include <iostream>
|
|
#include <fcntl.h>
|
|
#if defined(_WIN64) || defined(_WIN32)
|
|
#include <io.h>
|
|
#endif
|
|
#include <vector>
|
|
|
|
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);
|
|
|
|
#if defined(_WIN64) || defined(_WIN32)
|
|
_setmode(_fileno(stdout), _O_U16TEXT);
|
|
#endif
|
|
|
|
dbc::check(argc == 2, "USAGE: img2ansi <image_file>");
|
|
|
|
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 Point cell = {3, 6};
|
|
|
|
println("IMAGE SIZE {},{}", size.x, size.y);
|
|
RGBColor avg{0,0,0};
|
|
|
|
typedef vector<RGBColor> ColorRow;
|
|
vector<ColorRow> colors(size.x / cell.x, ColorRow(size.y / cell.y));
|
|
|
|
// LOL, so bad but just the start
|
|
for(unsigned int i = 0; i < size.x / cell.x; i++) {
|
|
for(unsigned int j = 0; j < size.y / cell.y; j++) {
|
|
|
|
// sum the cell
|
|
for(unsigned int x = 0; x < cell.x ; x++) {
|
|
for(unsigned int y = 0; y < cell.y ; y++) {
|
|
auto pixel = image.getPixel((i*cell.x) + x, (j * cell.y) + y);
|
|
|
|
avg.r += pixel.r;
|
|
avg.g += pixel.g;
|
|
avg.b += pixel.b;
|
|
}
|
|
}
|
|
|
|
// average it for the cell size
|
|
RGBColor color = {
|
|
avg.r / int(cell.x * cell.y),
|
|
avg.g / int(cell.x * cell.y),
|
|
avg.b / int(cell.x * cell.y),
|
|
};
|
|
|
|
// add it
|
|
colors[i][j] = color;
|
|
|
|
// reset
|
|
avg = {0,0,0};
|
|
}
|
|
}
|
|
|
|
Canvas drawing;
|
|
// create a grid panel to hold the cells
|
|
Panel panel(0, 0, 0, 0, true);
|
|
SFMLRender renderer;
|
|
renderer.resize_grid(26, panel);
|
|
|
|
drawing = Canvas(panel.width * 2, panel.height * 4);
|
|
panel.resize(240,240);
|
|
|
|
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;
|
|
|
|
int start_x = 0;
|
|
int start_y = 0;
|
|
int end_x = 600;
|
|
int end_y = 300;
|
|
int cur_x = start_x;
|
|
int cur_y = start_y;
|
|
|
|
sf::Texture texture;
|
|
texture.loadFromFile(image_file);
|
|
sf::Sprite sprite(texture);
|
|
|
|
panel.render();
|
|
|
|
while(renderer.is_open()) {
|
|
cur_x = cur_x < end_x ? cur_x + 1 : start_x;
|
|
cur_y = cur_y < end_y ? cur_y + 1 : start_y;
|
|
|
|
// sprite.setPosition(cur_x, cur_y);
|
|
// renderer.$window.draw(sprite);
|
|
// renderer.display();
|
|
|
|
renderer.draw(panel, cur_x, cur_y);
|
|
renderer.display();
|
|
|
|
while(renderer.poll_event(event)) {
|
|
if(event.type == sf::Event::Closed) {
|
|
renderer.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|