I've been doing the Perl Weekly
Challenges. This one dealt with
testing file contents and producing the current time.
Write a script to check the file content without explicitly reading
the content. It should accept file name with path as command line
argument and print “The file content is binary.” or else “The file
content is ascii.” accordingly.
OK, you want me to use file tests. Not much to this. (Not that I've
ever used them in real code, nor am I likely to.) They don't exist in
Perl6 as far as I know.
foreach (@ARGV) {
my $line='';
if (scalar @ARGV > 1) {
$line="$_: ";
}
$line .= 'The file content is ';
if (-T $_) {
$line.='ascii/utf8';
} else {
$line.='binary';
}
$line.=".\n";
print $line;
}
Write a script to display Digital Clock. Feel free to be as creative
as you can when displaying digits. We expect bare minimum something
like “14:10:11”.
Some other contestants have hard-coded ASCII-graphic font forms, after
the style of figlet. (As I write, nobody's used Text::FIGlet, though
someone shelled out to the actual figlet program - which seems like
cheating to me.)
But we can get excessively complex without that!
use Imager;
use Getopt::Std;
use POSIX qw(strftime);
my %o=(w => 80,
f => '/usr/share/fonts/truetype/msttcorefonts/Arial.ttf');
getopts('w:f:',\%o);
unless (-e $o{f}) {
die "Specify an existing ttf/otf font file with -f\n";
}
Yes, you need to specify a font file.
my $f=Imager::Font->new(file => $o{f});
my $base=500;
my $size=10;
my $t=strftime('%T',localtime);
So we draw the current time onto a blank canvas at a standard size,
then see how large it was in pixels.
my $i=Imager->new(xsize => $base,ysize => $base, channels => 1);
my @bounds=$i->align_string(string => strftime('%T',localtime),
font => $f,
x => 0,
y => 0,
halign => 'left',
valign => 'top',
size => $size,
);
Then scale the font size so that the second drawing will be about the
right width for the terminal window, and draw it again.
$size*=$o{w}/$bounds[2];
$base=$o{w};
$i=Imager->new(xsize => $base,ysize => $base, channels => 3);
my $w=Imager::Color->new(xname => 'white');
$i->box(color => $w,filled => 1);
my $b=Imager::Color->new(xname => 'black');
@bounds=$i->align_string(string => strftime('%T',localtime),
font => $f,
color => $b,
x => 0,
y => 0,
halign => 'left',
valign => 'top',
size => $size,
);
Now read that image one pixel at a time, representing darker pixels
with asterisks and lighter ones with spaces. (getscanline() would be
more efficient, as would memoising hsv given that we only have two
colours to worry about, or even using a paletted image rather than RGB,
but at this size it really doesn't matter.)
foreach my $yscan ($bounds[1]..$bounds[3]) {
foreach my $xscan ($bounds[0]..$bounds[2]) {
my @c=$i->getpixel(x => $xscan,y => $yscan)->hsv;
if ($c[2]<0.5) {
print '*';
} else {
print ' ';
}
}
print "\n";
}
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.