#!/usr/bin/env perl use warnings; use strict; # Animation frames... they are base64 encoded PNGs... I know, ridiculous. # But we want the animation to be as nice as possible right? my $frames = [ q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAOPs vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAbFJJyQAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAAD0SURBVCjPfZExasNAEEX3AnuENO5VLSrVuU1lthGoDblB KhduzDR7ABcuVeYExjeIQTgYppm75P/dlZFCyGs+zNOXtDvuCziQ01vFzaMn36Ey/Va30MZM6Kg+ AMfMW8B47GPcPdXMvu1LK/6hOB4efew8vrYBHDOL0oSWpqIyjd0bqD6qPGInKyXWlJYkU6otoNm+ arI2jlSkqoKJsfUphWmhUGtRGuSA3gvUCVAgLLcGSSpqVc1QjcPxne97W6tzwG1AaRKFugCOmed8 vSrYCo98WWB5KV39waW64qy2WmbRCC925dOavExuhbfJW05n7l9+ALhC6vmFWjsQAAAAAElFTkSu QmCC ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAOSl vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAKe6grwAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAAESSURBVCjPfZGhTsRAEIbXQx8B05CgTm0qa0gN4hRZ0wR7 DoOpAYEhY8ZhNqSyHntpLsFhekkDIRmz78I/u3elJYTPTPJ/M9vprhmG4c0YcxprFg4YZZjzaQ+M v9XeFi5iS1VN09wjfde6t4i72rnro5p4KOo05f5QMQ81FDbJ8/wC6Z3WpG7oy5UZjaomVlA1FLtS FipEpVMUAkFVVXWJ/Lxa0wdUF5USVWKNXp3qJCn+UZUQFxhyQmdEj8LGe/+M/Mr7Vjh+SygQc1JH Wj2wc7LR855u58q3Vm9DNkzCUH3fb5G+aG3j9eK/8CzYsJ+xS48iacGFEg4T8cXMCdJXrcI7nGNw f9hvCVpjdxizYP7jG3mC6097gdGNAAAAAElFTkSuQmCC ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAN4y vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAJP2l1QAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAADoSURBVCjPZZExCsJAEEX3Ah7BJr3VkjJdWivZJmBrZ21l YSPTzAFSWOYU4g0UAiJMM3fxz+4qu+QR+JDH30xmnQNPUGbmWfLSzFK9fWb+qROwPPs2RHxn6lRw 9ng9DSHslqodUiv8VQMsN+k8HaAwSVOQ1J4+oVvRvFADFIdOsuqB5Ta3SJWg+gKoKSqjVmqtSZLi qEaAjmqLUhBaE12E3fjjJsTxW0JKzJUitgOnIAc773qM6g7GUfXhbRtyYBKGuhc84nrxX7gWTFip dCmSBozKdmm5Yv0zuwosDoM5J2wrrJXaExOtL8p36js7BZOGAAAAAElFTkSuQmCC ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAB1C vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAbj0/bAAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAAELSURBVCjPZZGhasRAEIbXt/cINaFwqipExpSYilNlTaD2 XE1NTE/UlDHjasJRGX+2LIG6mhQCpTBQ9l36z24ubMgnMrDfzu7kX2OMuRyG4TOpZ4aUbz+xVj/5 xDipr6ZpnrUe8sIG8lJVk3DIsdzV1t6vVVHHLntWT1mWbbXexPN8DYVJsoSoHujXlhsaV6qGYltK VNdVVd1q3U1d5D1BVQlQXVDKQu28dnUSFau6a9v2DUa4QJMVuiJ6ETbtjBCHu4Q8MafqHZdDdVb2 et7ro6qjc+4D6q/PNQ3ZMwlDuRnv+hAv/gvPggldQh8fReKAqk6I8kKrsJ8ZzQJhjc7gg/mWYGvY 7ccNgv8H2I/sSNovpXIAAAAASUVORK5CYII= ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAFy1 vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAApXi9dgAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAADwSURBVCjPZZE9asQwEIV9AR8hTfpUwqW7bVMFNQa3ITdI tUWaMI0O4MKly5wg5Aa7INgsTDN3yXtjKdj4w3hgPr1BP80FNKDWDZctVysc1S0UMtU7YJf1Grro hL6qyjmgvQwxvhxVN6yp6OoRsM169nnjfYh9m1dVeXKlCSlNRzVElXvsBeoE2D49229JSTKtylEx 6+JCRbbKRIypL1nJzQRopsksdQiN8oHcQ1GF2VOjJBW1vZpmqGX8fOO819x8A7ZZ54DbgNIkWlTF /Hq5VeORN+bH/FH6skGHfRRfvnvMfzS1XIwfx+2wzI+1ZegPZM3s4CtHXV4AAAAASUVORK5CYII= ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAPGe vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAGyN1JAAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAAERSURBVCjPZZEha8RAEIXj2/yEmlCoqloiY8qailNlTCC2 VNfE9ERNWbOuZimRkYWzRyjU1eQgtByM2f/SN7t7d7m7T+zA+5jHJpuN4/idZdllmnPGORufOFd/ KjGJatv2BeGPzI0qKaCqpPYsFeK+Jno4VyViarZEVY7KoihukD7LXIY+tjVVbIPacxuV2VJljpQP qoaynkVpre+QX+uF+d1tCVFFFsb7knpqTGQ6KI0S2fo0r9i7gnLOvSO/d65jW/a4u7Fs2Ee1o/Oy 1bw9Sd/jkXIdVA/F1jDUMAxrpB8yO1WHG+LXyycPM3z4vU264Fx92fgohxfLLhCvMENTxJ48ONtc enDwqfJTLj04wvwHlF3r541YQ/UAAAAASUVORK5CYII= ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAF7J vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAp/JZbAAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAADwSURBVCjPfZExisMwEEV1AR9hG/euhEt3blMtagxul9wg VYo0YRodIMWWLnOC4BskYBIC08xd8mcsGyUs+5oP8/yNpHEOXIHlTRJuGa88fGL6VDdfB8M3i9oB zb3HeOhC+Da1y9jX3dwKfygd988uNMU0qxJoVqY4osXRuXKhkruqLjA9Q0NviiS1KAovqgVlxVHq MKhSoNoVIdHWmWamTG041ij1dEDvK6kT0Jq1eopMLFCnDFVDf9zq/37e1a/Ha0BxJE7qAjRHe14m bEWvfMkQW0qTDpirEXeVbJk6c3OOJIV+zdEip5CpEEsn7l9evlnr5WrqxEIAAAAASUVORK5CYII= ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFANuU vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAd2wdKwAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAAEOSURBVCjPfZGhTgQxEEDr4T4B05CgTjUr15AaxClSswn2 HAazhhMYMmYcpiEn12PJ5hIcZi/ZBEjG9F+Yme5xXUJ4opP0zbTTqTHGnA7D8KZxnyaMMJR8uInx t9q7KiiuntR727b3EjeOt7smhGtVbcGmanJV+EPpfmpYJVV31toLiUtVN/AV6gWMxhaIalhhqGmm kj1UQUqQ1bn3/tIu4XNVhU6VMBp/YMW5UtVRVnhUngArLgoEZwAPpOoqxvjEZYR6F0ECRFbxyFYO 7AKt5bzH21LFrZNp0BqBMKvnvu9fJe50vPwu/hbusC/Y5U+h3OBMEaYfRlUvPOUTiYQyOsML9zeH UyWbl0Uy//ENvvzsX2R5MJUAAAAASUVORK5CYII= ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAC6u vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAVagG9QAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAADtSURBVCjPZZExisNADEV9gT1CmvRbDS7dpd1qUWPYNl3q rVKkCWp0ABcufQqTGyRgCAE1usvqazxLBj8MH/Qseaxp7k7jlHzj/s7DVrbqmVYWqF8HVeQjtRSk rqjCOXl56om+t6rtcxeF2jsoI895nvWuLKvCZ6gfflH3wctG9a6EOnV1cFBGli4241UVvlqaQoFa GbomzUqawUF5GEaz1ptIecd80ayCUVniW8rGIpViwcCJ9Ih511MzOzDzbDYmbEOPwiqrKtxivf5f fi1+wkrlS9F8wABl5E3sn6W+cV+c4m0VrLBWhifSu/4AO9DnffnLtkcAAAAASUVORK5CYII= ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAO6g vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAcA3KOAAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAAEQSURBVCjPZZItT8RAEEDXw/0ETEOCQm0qa0gN4hRZ0wR7 DoOp4QSGjBmH2Vwq67Fk0wSH6SVNCMkg5r8ws7s0PfpEJ5m3sx8zNeM4fhhjznNcMi45cmatvmxm UtW27ZMkPzUebekitspqZm8l3TfO3a1V2aQqF1VRFFeSfdS4T/txI4qjmrmO6h6+XbWBaaUaUegq ElXX9Y1kLzX+VQEzJDWzLV0flXKitqxVPSWFxnv/Kulb7zvCUoocwQXAM0WVIcB4FgED4lJ1crio 3tFO93t5MCGEdxGHMMBPZ7UbtEMgTCrDYYjtlXfJWOSGYcGQhkLpgsqZZN80EvLMdDpxQm2dkQ/h v59BlsbVPG2k8b8hhOjwxX93WAAAAABJRU5ErkJggg== ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAG5w vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAAkXIGSwAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAADvSURBVCjPZZExisMwEEVzAR8hjftUwqW7tKkWNQa3YW+Q KsU2YRodwEVKl3uCkBtkwWQxTDN32f8lJSvjh/GAn/5IHm024AHKmnmU/FhmrX5dZnqpE2A9u8ZH XEt1Kjg7fB477z/WqulSyr9VDVh3sV8/d76tsFtdkJQGpDSsVedVZt9KVntQ7+x5SCkJplT7Fypm jR+pSKlMxJj6lsQU1QDgLDQI9fKF3BZq+OcaU70EFbWlGq5QY3/5ZL9jUjfAeneYBpQGUahbgcXx 8qjGXy7M3eKltPmAUXGWKHH54jLfaKi4GC+2W2ATH9aKoT9jaO/jJXUUeQAAAABJRU5ErkJggg== ), q( iVBORw0KGgoAAAANSUhEUgAAADQAAAAVBAMAAAD7ptBLAAAAAXNSR0IArs4c6QAAACpQTFRFAMll vf/3//8A/8yZM/8A/5n//5mZ/5kAmZmZAJn//zOZZjP//wAAAAAA4F2XugAAAAF0Uk5TAEDm2GYA AAAJcEhZcwAACxMAAAsTAQCanBgAAAENSURBVCjPZZEhawMxFMfjt/sIM2EwVRVOnhkxE1XjmYOz pXrmzCpmRkzcTBiVJwe15SjMzVzhoCs8k++y95Icza0/kT+8H+/xkgghxO0wDN9ZTgw5R5+4VieV GJP6adv2lXOjSgioilWbsVFU7mqA52tVUhmaM0BVjEG9SCkfOBdhHtoaKrRCyIykzBkqM1M+qJqU 9ZjUvdb6US7M7zJ1MaT0xNJ4X0IHjYmMF6VpCHd9mTfqu4vqyTn3QW1oy452NxYNelLuwtZzV/O+ 5nmrmXJbUh0ptAaj+uz7fs95UHXYkJ6er9xn+PC8TVowVwcbP2X6MSrtKG4ow6SIFXPQFjyHDvyv /FjwHDpC/gFKBu6aA6aScQAAAABJRU5ErkJggg== )]; use Image::Term256Color; use MIME::Base64; use Time::HiRes qw( usleep gettimeofday ); use Getopt::Long; use Pod::Usage; my $options = {}; GetOptions( "scale=f" => \$options->{scale_ratio}, "x_scale=i" => \$options->{scale_x}, "no_scale" => \$options->{no_scale}, "loop_times=i" => \$options->{loop_t}, "run_seconds=i" => \$options->{run_s}, "utf8" => \$options->{utf8}, "help" => \$options->{help} ); if( $options->{help} ){ print_usage(); } my $max_width = `tput cols`; $max_width = $options->{utf8} ? $max_width : sprintf("%u" , ($max_width / 2)); sub print_usage { pod2usage( { -message => $_[0] , -exitval => 1 , -verbose => 0 } ); } # Scale the animation per options set { my $img_opts; if( $options->{scale_ratio} ){ $img_opts->{scale_ratio} = $options->{scale_r}; } elsif( $options->{scale_x} ){ $img_opts->{scale_x} = $options->{scale_x}; } elsif( $options->{no_scale} ){ # Do nothing... } else { $img_opts->{scale_x} = $max_width; } $img_opts->{utf8} = $options->{utf8}; my $proc_img = sub { my $ascii = Image::Term256Color::convert( decode_base64($frames->[$_[0]]) , $img_opts ); if( !$ascii ){ print_usage("Error: Invalid image data or file.\n"); } return $ascii . "\n"; }; for(0..11){ $frames->[$_] = $proc_img->($_); } } # Loop the animation per options set my $loopcheck; if( $options->{loop_t} ){ $loopcheck = sub { if( $options->{loop_t} ){ $options->{loop_t}--; return 1; } else { return 0; } }; } elsif( $options->{run_s} ){ my $runtime = gettimeofday(); $loopcheck = sub { if( (scalar(gettimeofday()) - $runtime) < $options->{run_s} ){ return 1; } else { return 0; } }; } else { $loopcheck = sub { return 1; }; } # Clear the screen print "\033[2J"; # Animate! while($loopcheck->()){ my $frame = 0; while($frame < 12){ print "\033[0;0H"; # Jump to 0,0 print $frames->[$frame++]; usleep(70000); } } exit 0; __END__ =head1 NAME nyan - Your very own animated terminal Nyancat! =head1 SYNOPSIS nyan [options] Options: --help|-h brief help message --scale|-s scale image by the given ratio --x_scale|-x scale image to x 'pixels' wide --no_scale|-n do not scale the image at all --loop_times|-l number of times to loop the animation --run_seconds|-r number of seconds to run the animation --utf8|-u use utf8 half-blocks for pixels If Nyancat is larger than the current terminal in columns, it will be automatically scaled to fit unless specified. If no options are specified, Nyancat will loop forever. =head1 OPTIONS =over 8 =item --help|-h Prints a brief help message and exits. =item --scale|-s Scales Nyancat by the provided decimal ratio before printing. Superscedes --x_scale. =item --x_scale|-x Scales Nyancat width to match the provided integer in 'pixels'. Scales the image height proportionally. Superscedes --no_scale. =item --no_scale|-n Disables automatic scaling of Nyancat. =item --loop_times|-l Number of times to loop the Nyancat animation. =item --run_seconds|-r Number of seconds to run the Nyancat animation. Note: This isn't exact. =item --utf8|-u Uses utf8 'half-block' characters to effectlivy double the resolution in the terminal. May not display properly and depends on the font used. =back =head1 DESCRIPTION nyan a part of the L<Image::Term256Color> distribution and includes Nyancat animation frames within the script for enjoyment on 256 color terminals. =head1 EXAMPLES Run it already: nyan =cut