in reply to Imagecat - show color images in a terminal
And here is imagecat2, the full RGB color version with double the vertical resolution. As a bonus, each pixel (subpixel?) is now much more square, so the aspect ratio in the image is now more true to the original image.
This will need a 24 bit color terminal. I only tested in on Linux (Xubuntu 22.04), so i can't guarantee that it will work on Mac, Microsoft Bob or even other Linux distributions without fiddling with the settings.
#!/usr/bin/env perl use v5.36; use strict; use warnings; use utf8; use Carp; use Convert::Color; use Term::ANSIScreen qw/:color/; use GD; use Data::Dumper; use Term::ReadKey; # This version of imagecat requires a 24 bit color terminal and an ava +ilable Unicode "Upper Half Block" # https://tintin.mudhalla.net/info/truecolor/ # https://www.compart.com/en/unicode/U+2580 my ($cols, $rows, $wpixels, $hpixels) = GetTerminalSize(); $rows = $rows * 2; # Thanks to Unicode, we can work with DOUBLE the re +solution! # Prevent auto-wrapping $cols--; $rows--; # "Greyscale" unicode blocks # This could be specified nicer, but seems to be a problem when postin +g to PerlMonks my $halfblock = chr(9600); utf8::encode($halfblock); my @termcolors; # Pre-generate colors foreach my $termcolor (qw[red yellow green cyan blue magenta white]) { my $tmp = color $termcolor . ' on black'; push @termcolors, $tmp; } # Iterate through all image filenames given on command line foreach my $fname (@ARGV) { print "------ $fname ------\n"; my $ok = 0; eval { printImage($fname); $ok = 1; }; if(!$ok) { print STDERR "ERROR: $!\n"; } print "\n"; } sub printImage($fname) { my $img = GD::Image->new($fname); my ($origw, $origh) = $img->getBounds(); my ($w, $h) = ($origw + 0, $origh + 0); my $divfactor = 1; if($w > $cols) { my $tmp = $w / $cols; #print "$w / $cols / $tmp\n"; if($tmp > $divfactor) { $divfactor = $tmp; } } if($h > $rows) { my $tmp = $h / $rows; #print "$h / $rows / $tmp\n"; if($tmp > $divfactor) { $divfactor = $tmp; } } if($divfactor > 1) { $w = int($w / $divfactor); $h = int($h / $divfactor); my $newpic = GD::Image->new($w, $h, 1); $newpic->copyResized($img, 0, 0, # DEST X Y 0, 0, # SRC X Y $w, $h, # DEST W H $origw, $origh, # SRC W H ); $img = $newpic; } my $lastfgcolor = ''; my $lastbgcolor = ''; my ($r, $g, $b); # Color vars for(my $y = 0; $y < $h; $y+=2) { for(my $x = 0; $x < $w; $x++) { # Foreground color my $index = $img->getPixel($x, $y); ($r,$g,$b) = $img->rgb($index); my $newfgcolor = "\e[38;2;" . join(';', $r, $g, $b) . "m"; if($newfgcolor ne $lastfgcolor) { $lastfgcolor = $newfgcolor; print $newfgcolor; } # Background color my $lowy = $y + 1; if($lowy == $h) { # End of image. need a black half-line ($r, $g, $b) = (0, 0, 0); } else { my $index = $img->getPixel($x, $lowy); ($r,$g,$b) = $img->rgb($index); } my $newbgcolor = "\e[48;2;" . join(';', $r, $g, $b) . "m"; if($newbgcolor ne $lastbgcolor) { $lastbgcolor = $newbgcolor; print $newbgcolor; } print $halfblock; #print utf8::encode("\N{FULL BLOCK}"); } ($r, $g, $b) = (0, 0, 0); $lastfgcolor = "\e[38;2;" . join(';', $r, $g, $b) . "m"; $lastbgcolor = "\e[48;2;" . join(';', $r, $g, $b) . "m"; print $lastfgcolor, $lastbgcolor, "\n"; } { my $reset = color 'reset'; print $reset; } return; }
imagecat2 uses the Unicode "Upper Half Block" to display two pixels per character. Basically, for every line of characters, i parse TWO lines of the image. The upper line is the foreground color and the lower the background.
I try to minimize the color change characters i print by only setting a new foreground or background color if that has changed from the last printed pixel, so you could save the result to a text file and use the normal "cat" program to display its contents when required. But it could still result in a relatively large file/slow printing when showing a colorful photo in a high resolution text terminal.
|
---|