#!/usr/bin/perl -w use strict; # Build 8bit ANSI palette sub generate_palette() { my @palette = ( [ 0, 0, 0], [0x80, 0, 0], [ 0, 0x80, 0], [0x80, 0x80, 0], [ 0, 0, 0x80], [0x80, 0, 0x80], [ 0, 0x80, 0x80], [0xc0, 0xc0, 0xc0], [0x80, 0x80, 0x80], [0xff, 0, 0], [ 0, 0xff, 0], [0xff, 0xff, 0], [ 0, 0, 0xff], [0xff, 0, 0xff], [ 0, 0xff, 0xff], [0xff, 0xff, 0xff], ); my @x = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff); for(my $r = 0; $r < 6; $r++) { for(my $g = 0; $g < 6; $g++) { for(my $b = 0; $b < 6; $b++) { push @palette, [$x[$r], $x[$g], $x[$b]]; } } } my @gray = (0x08, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e, 0x58, 0x62, 0x6c, 0x76, 0x80, 0x8a, 0x94, 0x9e, 0xa8, 0xb2, 0xbc, 0xc6, 0xd0, 0xda, 0xe4, 0xee); foreach my $i (@gray) { push @palette, [$i, $i, $i]; } return @palette; } # Select nearest color from palette sub get_color_code($$$$) { my ($palette, $r, $g, $b) = @_; my $best = 0; my $diff = 1 << 31; for(my $i = 0; $i < scalar @$palette; $i++) { my $dr = $r - $$palette[$i][0]; my $dg = $g - $$palette[$i][1]; my $db = $b - $$palette[$i][2]; my $d = $dr * $dr + $dg * $dg + $db * $db; if( $diff > $d ) { $best = $i; $diff = $d; } } return "\e[48;5;${best}m"; } # Generate palette my @palette = generate_palette(); # Load image my $data = join '', <>; unless( $data =~ /^P6\s(\d+)\s+(\d+)\s255.(.*)$/s ) { die "Failed to parse PPM header\n"; } my ($width, $height, $pixels) = ($1, $2, $3); if( length($pixels) != $width * $height * 3 ) { die "Unexpected pixel data size, expected $width * $height * 3 = " . ($width * $height * 3) . ", got " . length($pixels) . "\n"; } # Convert pixels my $offset = 0; for(my $y = 0; $y < $height; $y++) { for(my $x = 0; $x < $width; $x++) { my $r = ord(substr($pixels, $offset++, 1)); my $g = ord(substr($pixels, $offset++, 1)); my $b = ord(substr($pixels, $offset++, 1)); print get_color_code(\@palette, $r, $g, $b), " "; } print "\e[0m\n"; }