MCPcopy Create free account
hub / github.com/bshoshany/thread-pool / plot_image_chars

Function plot_image_chars

tests/BS_thread_pool_test.cpp:3505–3590  ·  view source on GitHub ↗

* @brief Create a plot of an image as characters, using either 24-bit ANSI colors or monochrome blocks of different brightness. * * @param image The image to plot. * @param out_width The plot width in terminal characters. Should be even, since in the monochrome case each pixel spans two characters horizontally. * @param use_color `true` to generate a colored plot, `false` to generate a monochr

Source from the content-addressed store, hash-verified

3503 * @return The plot as a string.
3504 */
3505std::string plot_image_chars(const image_matrix<color>& image, const std::size_t out_width, const bool use_color)
3506{
3507 // Get the source image dimensions.
3508 const std::size_t src_width = image.get_width();
3509 const std::size_t src_height = image.get_height();
3510 // Compute the plot height in terminal characters, keeping in mind that characters have an aspect ratio of about 1:2 (width:height).
3511 const std::size_t out_height = static_cast<std::size_t>(std::llround(0.5 * static_cast<double>(src_height) * static_cast<double>(out_width) / static_cast<double>(src_width)));
3512 // Create a buffer for the plot.
3513 std::string plot;
3514
3515 // For the colored plot we use Unicode lower half blocks to pack two pixels per character. The background color sets the color of the top (empty) half, and the foreground color sets the color of the bottom (filled) half.
3516 if (use_color)
3517 {
3518 // Each character row contains two pixel rows (top and bottom).
3519 const std::size_t out_height_pixels = out_height * 2;
3520 // Create a mapping of output x coordinates to source pixels, such that x_map[0] = 0 and x_map[out_width - 1] = src_width - 1.
3521 std::vector<std::size_t> x_map(out_width);
3522 for (std::size_t x = 0; x < out_width; ++x)
3523 x_map[x] = (x * (src_width - 1)) / (out_width - 1);
3524 // Create a mapping of output pixel y coordinates to source pixels, such that y_map[0] = 0 and y_map[out_height_pixels - 1] = src_height - 1.
3525 std::vector<std::size_t> y_map(out_height_pixels);
3526 for (std::size_t y = 0; y < out_height_pixels; ++y)
3527 y_map[y] = (y * (src_height - 1)) / (out_height_pixels - 1);
3528 // Reserve enough capacity for the entire plot to avoid reallocations. Each row contains ANSI codes of the form `\033[48;2;RRR;GGG;BBBm\033[38;2;RRR;GGG;BBBm` = up to 38 bytes, plus the Unicode lower half block U+2584 in UTF-8 = 3 bytes, for a total of 41 bytes per character of the plot, plus the `\033[0m` reset code at the end and the newline = 5 bytes.
3529 plot.reserve(out_height * ((out_width * 41) + 5));
3530 // Iterate over the rows and columns.
3531 for (std::size_t y = 0; y < out_height; ++y)
3532 {
3533 for (std::size_t x = 0; x < out_width; ++x)
3534 {
3535 // Fetch the sampled source pixel for the top and bottom halves.
3536 const color col_top = image(x_map[x], y_map[2 * y]);
3537 const color col_bottom = image(x_map[x], y_map[(2 * y) + 1]);
3538 // Create the background color ANSI sequence for the top half.
3539 plot.append("\033[48;2;");
3540 plot.append(std::to_string(col_top.r));
3541 plot.push_back(';');
3542 plot.append(std::to_string(col_top.g));
3543 plot.push_back(';');
3544 plot.append(std::to_string(col_top.b));
3545 // Finish the sequence with `m` and create the foreground color ANSI sequence for the bottom half.
3546 plot.append("m\033[38;2;");
3547 plot.append(std::to_string(col_bottom.r));
3548 plot.push_back(';');
3549 plot.append(std::to_string(col_bottom.g));
3550 plot.push_back(';');
3551 plot.append(std::to_string(col_bottom.b));
3552 // Finish the sequence with `m` and append a lower half block (U+2584) in UTF-8, which is the actual character that will be displayed.
3553 plot.append("m\xE2\x96\x84");
3554 }
3555 // Reset the ANSI style at the end of the row and add a newline character.
3556 plot.append("\033[0m\n");
3557 }
3558 }
3559 // For the monochrome plot we use Unicode block characters of different brightness levels. Each pixel is rendered as two identical blocks side-by-side to make the pixels square (so essentially, the opposite of the colored plot).
3560 else
3561 {
3562 // Each pixel spans two terminal characters horizontally.

Callers 1

check_performanceFunction · 0.85

Calls 3

brightness_blockFunction · 0.85
get_widthMethod · 0.80
get_heightMethod · 0.80

Tested by

no test coverage detected