A few days ago a played around with displaying (color) ASCII art in a Terminal in Re: 80x25 ASCII text art in terminal, because harangzsolt33 peaked my interest. i mentioned that it should be possible to display low res color images in the text console as well and that i would look into it if someone was interested.
Turns out, the first interested party was myself. Literally a couple of hours after i posted, i had to sort through some PNG icons through an SSH connection. "Instead of downloading the folder, opening the files locally and finding the correct icon, wouldn't it be nice to just display a low res version in my terminal?". Yes, i know there are technically a few other tools that can already do this. But i decided i wanted a Perl version, so that i can easily customize it to my liking. I wanted to build it in a way that it ONLY uses very basic ANSI colors, to support as many color terminals as possible (and as long as they support Unicode).
So, i created imagecat:
#!/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; my ($cols, $rows, $wpixels, $hpixels) = GetTerminalSize(); # Prevent auto-wrapping $cols--; $rows--; # "Greyscale" unicode blocks # This could be specified nicer, but seems to be a problem when postin +g to PerlMonks, see comment below my @shades; foreach my $char (qw(32 9617 9618 9619 9608)) { my $tmp = chr($char); utf8::encode($tmp); push @shades, $tmp; } 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 $lastcindex = -1; for(my $y = 0; $y < $h; $y++) { for(my $x = 0; $x < $w; $x++) { my $index = $img->getPixel($x, $y); my ($r,$g,$b) = $img->rgb($index); #my $grey = int(($r + $g + $b) / 3); my $basecolor = Convert::Color->new('rgb8:' . join(',', $r +, $g, $b)); my ($ph, $ps, $pv) = $basecolor->as_hsv->hsv; my $colormode = 0; if($ps > 0.5) { $colormode = 1; } # Map the brightness to the corresponding Unicode characte +rs my $brightness = int($pv * 4); if(!defined($shades[$brightness])) { croak("Undefined $pv -> $brightness"); } my $shade = $shades[$brightness]; # Map the color to roughly their corresponding ANSI termin +al color code. my $cindex = 0; if($ps < 0.5) { # White $cindex = 6; } elsif($ph > 34 && $ph <= 82) { # Yellow $cindex = 1; } elsif($ph > 82 && $ph <= 159) { # Green $cindex = 2; } elsif($ph > 159 && $ph <= 205) { # Cyan $cindex = 3; } elsif($ph > 205 && $ph <= 270) { # Blue $cindex = 4; } elsif($ph > 270 && $ph <= 330) { # Magenta $cindex = 5; } else { # Red $cindex = 0; } if($cindex != $lastcindex) { print $termcolors[$cindex]; $lastcindex = $cindex; } print $shade; } print "\n"; } { my $reset = color 'reset'; print $reset; } return; }
Had a slight problem posting the original code to PerlMonks. The while @shades initialization is a single line in my original code, but PM refused to show Unicode in code tags. Basically, this is what it should look like (that is, unless there are more PM rendering bugs):
my @shades = (' ', '░', '▒', '▓', '█');
Yes, this could be improved with using full RGB colors and 2 "pixels" per character using something like 'Upper half block ▀' for a higher resolution. But for now, i just wanted to learn if i can do a version with much more basic color support. HSV color mapping is a strange beast... Edit: I wrote the full color, double-vertical resolution imagecat2, see my post below.
|
---|