#!/usr/bin/perl use IO::File; use Encode::Unicode; use Pod::Usage; use Getopt::Std; use Encode; getopts('e:h'); unless ($ARGV[0] || $opt_h) { pod2usage(1); exit; } if ($opt_h) { pod2usage(-verbose => 2, -noperldoc => 1); exit; } my (@chars, $currchar, $fontname, $ascent, $descent, %pmap); if ($opt_e) { foreach my $e (split(/[,;\s]+/, $opt_e)) { my (@f) = split(/=/, $e); foreach my $f (@f[1..$#f]) { $pmap{$f} = $f[0]; } } } $s = Font::TTF::Scripts::SFD->new( 'FontName' => sub {$fontname = $_[0]; }, 'Ascent' => sub {$ascent = $_[0]; }, 'Descent' => sub {$descent = $_[0]; }, 'StartChar' => sub { my ($name) = @_; $name =~ s/\s*$//o; $currchar = {'name' => $name}; }, 'Encoding' => sub { my ($str) = @_; my (@vals) = split(' ', $str); $currchar->{'UID'} = $vals[1]; $chars[$vals[2]] = $currchar; }, 'AnchorPoint' => sub { my ($str) = @_; my (@values) = split(' ', $str); my ($name) = $values[0]; $name =~ s/^(['"])(.*?)\1/$2/o; # "' $name = $pmap{$name} if (defined $pmap{$name}); $name = "_$name" if (($values[3] eq 'mark' or $values[3] eq 'entry') && $name !~ m/^_/o); $currchar->{'points'}{$name} = [$values[1], $values[2]]; }, 'Comment' => sub { my ($text) = @_; $currchar->{'comment'} = decode('UTF-7', $text); $currchar->{'comment'} =~ s/^"//o; $currchar->{'comment'} =~ s/"$//o; }); $s->parse_file($ARGV[0]); $upem = $ascent + $descent; # sigh! if ($ARGV[1]) { $outfh = IO::File->new("> $ARGV[1]") || die "Can't open $ARGV[1]"; select $outfh; } print <<"EOT"; EOT foreach $c (@chars) { next unless (defined $c->{'name'}); printf('{'name'}); printf(' UID="%04X"', $c->{'UID'}) if ($c->{'UID'} > 0); # don't output gid it doesn't tie up with generated font if (defined $c->{'points'} || defined $c->{'comment'}) { print ">\n"; foreach $p (sort keys %{$c->{'points'}}) { printf(" \n \n \n", $p, @{$c->{'points'}{$p}}); } while ($c->{'comment'} =~ s/^(\w+):\s+(.*?)\s*$//om) { print (" \n"); } print(" $c->{'comment'}\n") if (defined $c->{'comment'}); print "\n"; } else { print "/>\n"; } } print "\n\n"; $outfh->close if ($ARGV[1]); package Font::TTF::Scripts::SFD; use IO::File; sub new { my ($class, %info) = @_; my ($self) = {%info}; return bless $self, ref $class || $class; } sub parse_file { my ($self, $fname) = @_; my ($fh); my ($command, $text); if (ref $fname) { $fh = $fname; } else { $fh = IO::File->new("< $fname") || die "Can't open $fname for reading"; } while (<$fh>) { if (m/^\s/o || m/^\d/o) { $text .= $_; next; } elsif (defined $self->{$command}) { $text =~ s/\s*$//os; &{$self->{$command}}($text); $command = ''; $text = ''; } if (s/^([^\s:]+):\s*//o) { $command = $1; $text = $_; } else { s/\s*$//o; $command = $_; } } if (defined $self->{$command}) { &{$self->{$command}}($text); } } __END__ =head1 TITLE sfd2ap - export anchor points from a FontForge file =head1 SYNOPSIS sfd2ap infile.sfd [outfile.xml] Reads a FontForge font file and extracts anchor point information into an XML anchor point database. =head1 OPTIONS -h print manpage -e X=Y,Z=W=A equates attachment points =head1 DESCRIPTION FontForge's has the concept of anchor points. This program extracts those and any glyph comments into an XML anchor point database. See ttfbuilder -h for documentation on this format. =head1 SEE ALSO ttfbuilder, volt2ap =cut