|
22 | 22 |
|
23 | 23 | #include <crispy/App.h>
|
24 | 24 | #include <crispy/StackTrace.h>
|
| 25 | +#include <crispy/base64.h> |
25 | 26 | #include <crispy/utils.h>
|
26 | 27 |
|
27 | 28 | #include <fmt/chrono.h>
|
@@ -57,6 +58,7 @@ using std::string_view;
|
57 | 58 | using std::unique_ptr;
|
58 | 59 |
|
59 | 60 | using namespace std::string_literals;
|
| 61 | +using namespace std::string_view_literals; |
60 | 62 |
|
61 | 63 | namespace CLI = crispy::cli;
|
62 | 64 |
|
@@ -279,6 +281,106 @@ int ContourApp::captureAction()
|
279 | 281 | return EXIT_FAILURE;
|
280 | 282 | }
|
281 | 283 |
|
| 284 | +#if defined(GOOD_IMAGE_PROTOCOL) |
| 285 | +namespace |
| 286 | +{ |
| 287 | + crispy::Size parseSize(string_view _text) |
| 288 | + { |
| 289 | + (void) _text; |
| 290 | + return crispy::Size {}; // TODO |
| 291 | + } |
| 292 | + |
| 293 | + terminal::ImageAlignment parseImageAlignment(string_view _text) |
| 294 | + { |
| 295 | + (void) _text; |
| 296 | + return terminal::ImageAlignment::TopStart; // TODO |
| 297 | + } |
| 298 | + |
| 299 | + terminal::ImageResize parseImageResize(string_view _text) |
| 300 | + { |
| 301 | + (void) _text; |
| 302 | + return terminal::ImageResize::NoResize; // TODO |
| 303 | + } |
| 304 | + |
| 305 | + // terminal::CellLocation parsePosition(string_view _text) |
| 306 | + // { |
| 307 | + // (void) _text; |
| 308 | + // return {}; // TODO |
| 309 | + // } |
| 310 | + |
| 311 | + // TODO: chunkedFileReader(path) to return iterator over spans of data chunks. |
| 312 | + std::vector<uint8_t> readFile(FileSystem::path const& _path) |
| 313 | + { |
| 314 | + auto ifs = std::ifstream(_path.string()); |
| 315 | + if (!ifs.good()) |
| 316 | + return {}; |
| 317 | + |
| 318 | + auto const size = FileSystem::file_size(_path); |
| 319 | + auto text = std::vector<uint8_t>(); |
| 320 | + text.resize(size); |
| 321 | + ifs.read((char*) &text[0], static_cast<std::streamsize>(size)); |
| 322 | + return text; |
| 323 | + } |
| 324 | + |
| 325 | + void displayImage(terminal::ImageResize _resizePolicy, |
| 326 | + terminal::ImageAlignment _alignmentPolicy, |
| 327 | + crispy::Size _screenSize, |
| 328 | + string_view _fileName) |
| 329 | + { |
| 330 | + auto constexpr ST = "\033\\"sv; |
| 331 | + |
| 332 | + cout << fmt::format("{}f={},c={},l={},a={},z={};", |
| 333 | + "\033Ps"sv, // GIONESHOT |
| 334 | + '0', // image format: 0 = auto detect |
| 335 | + _screenSize.width, |
| 336 | + _screenSize.height, |
| 337 | + int(_alignmentPolicy), |
| 338 | + int(_resizePolicy)); |
| 339 | + |
| 340 | + #if 1 |
| 341 | + auto const data = readFile(FileSystem::path(string(_fileName))); // TODO: incremental buffered read |
| 342 | + auto encoderState = crispy::base64::EncoderState {}; |
| 343 | + |
| 344 | + std::vector<char> buf; |
| 345 | + auto const writer = [&](char a, char b, char c, char d) { |
| 346 | + buf.push_back(a); |
| 347 | + buf.push_back(b); |
| 348 | + buf.push_back(c); |
| 349 | + buf.push_back(d); |
| 350 | + }; |
| 351 | + auto const flush = [&]() { |
| 352 | + cout.write(buf.data(), static_cast<std::streamsize>(buf.size())); |
| 353 | + buf.clear(); |
| 354 | + }; |
| 355 | + |
| 356 | + for (uint8_t const byte: data) |
| 357 | + { |
| 358 | + crispy::base64::encode(byte, encoderState, writer); |
| 359 | + if (buf.size() >= 4096) |
| 360 | + flush(); |
| 361 | + } |
| 362 | + flush(); |
| 363 | + #endif |
| 364 | + |
| 365 | + cout << ST; |
| 366 | + } |
| 367 | +} // namespace |
| 368 | + |
| 369 | +int ContourApp::imageAction() |
| 370 | +{ |
| 371 | + auto const resizePolicy = parseImageResize(parameters().get<string>("contour.image.resize")); |
| 372 | + auto const alignmentPolicy = parseImageAlignment(parameters().get<string>("contour.image.align")); |
| 373 | + auto const size = parseSize(parameters().get<string>("contour.image.size")); |
| 374 | + auto const fileName = parameters().verbatim.front(); |
| 375 | + // TODO: how do we wanna handle more than one verbatim arg (image)? |
| 376 | + // => report error and EXIT_FAILURE as only one verbatim arg is allowed. |
| 377 | + // FIXME: What if parameter `size` is given as `_size` instead, it should cause an |
| 378 | + // invalid-argument error above already! |
| 379 | + displayImage(resizePolicy, alignmentPolicy, size, fileName); |
| 380 | + return EXIT_SUCCESS; |
| 381 | +} |
| 382 | +#endif |
| 383 | + |
282 | 384 | int ContourApp::parserTableAction()
|
283 | 385 | {
|
284 | 386 | terminal::parser::parserTableDot(std::cout);
|
@@ -366,6 +468,35 @@ crispy::cli::Command ContourApp::parameterDefinition() const
|
366 | 468 | "FILE",
|
367 | 469 | CLI::Presence::Required },
|
368 | 470 | } } } },
|
| 471 | +#if defined(GOOD_IMAGE_PROTOCOL) |
| 472 | + CLI::Command { |
| 473 | + "image", |
| 474 | + "Sends an image to the terminal emulator for display.", |
| 475 | + CLI::OptionList { |
| 476 | + CLI::Option { "resize", |
| 477 | + CLI::Value { "fit"s }, |
| 478 | + "Sets the image resize policy.\n" |
| 479 | + "Policies available are:\n" |
| 480 | + " - no (no resize),\n" |
| 481 | + " - fit (resize to fit),\n" |
| 482 | + " - fill (resize to fill),\n" |
| 483 | + " - stretch (stretch to fill)." }, |
| 484 | + CLI::Option { "align", |
| 485 | + CLI::Value { "center"s }, |
| 486 | + "Sets the image alignment policy.\n" |
| 487 | + "Possible policies are: TopLeft, TopCenter, TopRight, MiddleLeft, " |
| 488 | + "MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight." }, |
| 489 | + CLI::Option { "size", |
| 490 | + CLI::Value { ""s }, |
| 491 | + "Sets the amount of columns and rows to place the image onto. " |
| 492 | + "The top-left of the this area is the current cursor position, " |
| 493 | + "and it will be scrolled automatically if not enough rows are present." } }, |
| 494 | + CLI::CommandList {}, |
| 495 | + CLI::CommandSelect::Explicit, |
| 496 | + CLI::Verbatim { |
| 497 | + "IMAGE_FILE", |
| 498 | + "Path to image to be displayed. Image formats supported are at least PNG, JPG." } }, |
| 499 | +#endif |
369 | 500 | CLI::Command {
|
370 | 501 | "capture",
|
371 | 502 | "Captures the screen buffer of the currently running terminal.",
|
|
0 commit comments