#! /usr/bin/perl use strict; use Font::TTF::Useall; use Pod::Usage; # Can't use GetOpt variants because of the funky syntax of -m and -M (see perlrun) my (@modules, $prog, $opt_v, $output, $exe); while(scalar (@ARGV) >= 0) { my $arg = shift; if ($arg =~ /^-\?/o) { pod2usage( -verbose => 2, -noperldoc => 1); exit; } if ($arg =~ /^-([mM])([^-].*)$/o) { push @modules, [ $1, $2 ]; } # Save -m or -M and their args for later elsif ($arg =~ /^-e$/o) { $prog .= shift() . "\n"; } # Concatinate -e arguments -- that's the user's program. elsif ($arg =~ /^-o(.*)$/o) { die "Only one -o option allowed." if defined $output; $output = $1 || shift; # Remember outputfile } elsif ($arg =~ m/^-v$/o) { $opt_v = 1; } else { unshift (@ARGV, $arg); last; } } pod2usage(-msg => "missing infont.ttf parameter\n", -verbose => 1) unless defined $ARGV[0]; # 'require' modules specified on -m or -M -- this is intended to mimic what perl -m or perl -M does foreach (@modules) { my ($c, $m) = @{$_}; # $c is either 'm' or 'M'; $m is the module name plus any extra info user gave $m =~ s/^\s+//o; $m =~ s/\s+$//o; my $res; if ($m =~ /^(\S+)\s*=\s*(.*)$/o) # 'module=something' { eval "\$res = require $1; $1->import(split(/,/,'$2'));" ; } elsif ($m =~ /^(\S+)\s+(.*)$/o) # 'module something' { eval "\$res = require $1; $1->import($2);" ; } else # 'module' { eval "\$res = require $m; $m->import unless \$c eq 'm';" ; } die "Couldn't find module '$m'\n" unless $res; } # Open the font: my ($f); { no strict; $exe = eval "sub{ $prog }" if ($prog ne ""); die $@ if $@; } $output =~ s|\\|/|og; my ($out_rep) = $output; my ($i); $out_rep =~ s/[?*]/'$m[' . ($i++) . ']'/oge; foreach my $a (@ARGV) { $a =~ s|\\|/|og; my ($sub) = $a; $sub =~ s/\*/([^.]*)/og; $sub =~ s/\?/(.?)/og; foreach my $infile (glob($a)) { my (@m) = ($infile =~ m/$sub/g); my ($outfile); if ($output && -d $output) # then get filename and append { if ($infile =~ m|[\\/]([^/\\]+)$|o) { $outfile = "$output/$1"; } else { $outfile = "$output/$f"; } } elsif ($output) # replace wildcards with corresponding wildcard matches { $outfile = eval "\"$out_rep\""; } print STDERR "$infile -> $outfile\n" if ($opt_v); $f = Font::TTF::Font->open($infile) || die "Can't open font file '$infile': $!\n"; # Invoke user's script, if any: eval $exe->($infile, $outfile) if $prog; # Write the resultant font if requested if ($outfile) { $f->update; $f->out($outfile) || die "Failed writing output font file '$outfile': $!\n"; } } } =head1 TITLE ttfeval - wrapper for short L hacks =head1 SYNOPSIS tteval [options] infont.ttf ... =head1 OPTIONS =over =item B<-m>module =item B<-M>module =item B<-M>'module ...' =item B<-[mM]>module=arg[,arg]... =item B<-e> commandline Work essentially like the same options for Perl. See L. =item B<-o> outfont Indicates that you want an output font written, and names the font file. May take globs or be a directory. =item B<-?> Verbose help. =back =head1 DESCRIPTION ttfeval is a wrapper for those one- or two-line font hacks. It does the work of including the Font::TTF module, opening the input font file, and optionally writing the output font file. You just supply the code in the middle. For example, to list out all the glyph names of a font, use: ttfeval -e 'print join("\n",@{$f->{'post'}->read->{'VAL'}});' myfont.ttf Like the perl command line, you can specify multiple B<-e> options to build up a multiline program, and you can include additional modules via the B<-m> and B<-M> options. When the caller-supplied expression is executed, B<$f> holds the result of the Font::TTF::Font->open() function and elements of B<@ARGV> up to and including the input font name have been deleted -- you can use any remaining arguments for your own purposes. B<@_> holds the names of the names of the input and optional output font files -- changing B<$_[0]> has no effect, but setting or clearing B<$_[1]> will change the output. Globbing of file names is permitted: ttfeval -e 'print $f->{'name'}->read->find_name(4) . "\n"' *.ttf including the output name: ttfeval ... -o x*.ttf *.ttf =cut