|
19 | 19 |
|
20 | 20 | #include <terminal/Capabilities.h>
|
21 | 21 | #include <terminal/Parser.h>
|
| 22 | +#include <terminal/Image.h> |
22 | 23 |
|
23 | 24 | #include <crispy/StackTrace.h>
|
| 25 | +#include <crispy/base64.h> |
24 | 26 | #include <crispy/debuglog.h>
|
| 27 | +#include <crispy/stdfs.h> |
25 | 28 | #include <crispy/utils.h>
|
26 | 29 |
|
27 | 30 | #include <iostream>
|
|
35 | 38 | #include <sys/ioctl.h>
|
36 | 39 | #endif
|
37 | 40 |
|
| 41 | +#define GOOD_IMAGE_PROTOCOL // TODO use cmake here instead |
| 42 | + |
38 | 43 | using std::bind;
|
39 | 44 | using std::cerr;
|
40 | 45 | using std::cout;
|
| 46 | +using std::ifstream; |
41 | 47 | using std::make_unique;
|
42 | 48 | using std::ofstream;
|
43 | 49 | using std::string;
|
44 | 50 | using std::string_view;
|
45 | 51 | using std::unique_ptr;
|
| 52 | +using std::vector; |
46 | 53 |
|
47 | 54 | using namespace std::string_literals;
|
| 55 | +using namespace std::string_view_literals; |
48 | 56 |
|
49 | 57 | namespace CLI = crispy::cli;
|
50 | 58 |
|
@@ -202,6 +210,76 @@ namespace // {{{ helper
|
202 | 210 | #endif
|
203 | 211 | } // }}}
|
204 | 212 |
|
| 213 | +#if defined(GOOD_IMAGE_PROTOCOL) // {{{ |
| 214 | +terminal::ImageAlignment parseImageAlignment(string_view _text) |
| 215 | +{ |
| 216 | + (void) _text; |
| 217 | + return terminal::ImageAlignment::TopStart; // TODO |
| 218 | +} |
| 219 | + |
| 220 | +terminal::ImageResize parseImageResize(string_view _text) |
| 221 | +{ |
| 222 | + (void) _text; |
| 223 | + return terminal::ImageResize::NoResize; // TODO |
| 224 | +} |
| 225 | + |
| 226 | +terminal::Coordinate parsePosition(string_view _text) |
| 227 | +{ |
| 228 | + (void) _text; |
| 229 | + return {}; // TODO |
| 230 | +} |
| 231 | + |
| 232 | +// TODO: chunkedFileReader(path) to return iterator over spans of data chunks. |
| 233 | +std::vector<uint8_t> readFile(FileSystem::path const& _path) |
| 234 | +{ |
| 235 | + auto ifs = ifstream(_path.string()); |
| 236 | + if (!ifs.good()) |
| 237 | + return {}; |
| 238 | + |
| 239 | + auto const size = FileSystem::file_size(_path); |
| 240 | + auto text = vector<uint8_t>(); |
| 241 | + text.resize(size); |
| 242 | + ifs.read((char*) &text[0], size); |
| 243 | + return text; |
| 244 | +} |
| 245 | + |
| 246 | +void displayImage(terminal::ImageResize _resizePolicy, |
| 247 | + terminal::ImageAlignment _alignmentPolicy, |
| 248 | + crispy::Size _screenSize, |
| 249 | + string_view _fileName) |
| 250 | +{ |
| 251 | + auto constexpr ST = "\033\\"sv; |
| 252 | + |
| 253 | + cout << fmt::format("{}f={},c={},l={},a={},z={};", |
| 254 | + "\033Ps"sv, // GIONESHOT |
| 255 | + '0', // image format: 0 = auto detect |
| 256 | + _screenSize.width, |
| 257 | + _screenSize.height, |
| 258 | + int(_alignmentPolicy), |
| 259 | + int(_resizePolicy) |
| 260 | + ); |
| 261 | + |
| 262 | +#if 1 |
| 263 | + auto const data = readFile(_fileName);// TODO: incremental buffered read |
| 264 | + auto encoderState = crispy::base64::EncoderState{}; |
| 265 | + |
| 266 | + vector<char> buf; |
| 267 | + auto const writer = [&](string_view _data) { for (auto ch: _data) buf.push_back(ch); }; |
| 268 | + auto const flush = [&]() { cout.write(buf.data(), buf.size()); buf.clear(); }; |
| 269 | + |
| 270 | + for (uint8_t const byte: data) |
| 271 | + { |
| 272 | + crispy::base64::encode(byte, encoderState, writer); |
| 273 | + if (buf.size() >= 4096) |
| 274 | + flush(); |
| 275 | + } |
| 276 | + flush(); |
| 277 | +#endif |
| 278 | + |
| 279 | + cout << ST; |
| 280 | +} |
| 281 | +#endif // }}} |
| 282 | + |
205 | 283 | ContourApp::ContourApp() :
|
206 | 284 | App("contour", "Contour Terminal Emulator", CONTOUR_VERSION_STRING)
|
207 | 285 | {
|
@@ -301,6 +379,28 @@ int ContourApp::profileAction()
|
301 | 379 | return EXIT_SUCCESS;
|
302 | 380 | }
|
303 | 381 |
|
| 382 | +#if defined(GOOD_IMAGE_PROTOCOL) |
| 383 | +crispy::Size parseSize(string_view _text) |
| 384 | +{ |
| 385 | + (void) _text; |
| 386 | + return crispy::Size{};//TODO |
| 387 | +} |
| 388 | + |
| 389 | +int ContourApp::imageAction() |
| 390 | +{ |
| 391 | + auto const resizePolicy = parseImageResize(parameters().get<string>("contour.image.resize")); |
| 392 | + auto const alignmentPolicy = parseImageAlignment(parameters().get<string>("contour.image.align")); |
| 393 | + auto const size = parseSize(parameters().get<string>("contour.image.size")); |
| 394 | + auto const fileName = parameters().verbatim.front(); |
| 395 | + // TODO: how do we wanna handle more than one verbatim arg (image)? |
| 396 | + // => report error and EXIT_FAILURE as only one verbatim arg is allowed. |
| 397 | + // FIXME: What if parameter `size` is given as `_size` instead, it should cause an |
| 398 | + // invalid-argument error above already! |
| 399 | + displayImage(resizePolicy, alignmentPolicy, size, fileName); |
| 400 | + return EXIT_SUCCESS; |
| 401 | +} |
| 402 | +#endif |
| 403 | + |
304 | 404 | crispy::cli::Command ContourApp::parameterDefinition() const
|
305 | 405 | {
|
306 | 406 | return CLI::Command{
|
@@ -365,6 +465,37 @@ crispy::cli::Command ContourApp::parameterDefinition() const
|
365 | 465 | }
|
366 | 466 | }
|
367 | 467 | },
|
| 468 | +#if defined(GOOD_IMAGE_PROTOCOL) |
| 469 | + CLI::Command{ |
| 470 | + "image", |
| 471 | + "Sends an image to the terminal emulator for display.", |
| 472 | + CLI::OptionList{ |
| 473 | + CLI::Option{"resize", CLI::Value{"fit"s}, |
| 474 | + "Sets the image resize policy.\n" |
| 475 | + "Policies available are:\n" |
| 476 | + " - no (no resize),\n" |
| 477 | + " - fit (resize to fit),\n" |
| 478 | + " - fill (resize to fill),\n" |
| 479 | + " - stretch (stretch to fill)." |
| 480 | + }, |
| 481 | + CLI::Option{"align", CLI::Value{"center"s}, |
| 482 | + "Sets the image alignment policy.\n" |
| 483 | + "Possible policies are: TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight." |
| 484 | + }, |
| 485 | + CLI::Option{"size", CLI::Value{""s}, |
| 486 | + "Sets the amount of columns and rows to place the image onto. " |
| 487 | + "The top-left of the this area is the current cursor position, " |
| 488 | + "and it will be scrolled automatically if not enough rows are present." |
| 489 | + } |
| 490 | + }, |
| 491 | + CLI::CommandList{}, |
| 492 | + CLI::CommandSelect::Explicit, |
| 493 | + CLI::Verbatim{ |
| 494 | + "IMAGE_FILE", |
| 495 | + "Path to image to be displayed. Image formats supported are at least PNG, JPG." |
| 496 | + } |
| 497 | + }, |
| 498 | +#endif |
368 | 499 | CLI::Command{
|
369 | 500 | "capture",
|
370 | 501 | "Captures the screen buffer of the currently running terminal.",
|
|
0 commit comments