From 74a9e96c08d231fdf6d6cc49aafc4ac75ff0f621 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 26 Jun 2019 20:41:25 +0000 Subject: fontools (26jun19) git-svn-id: svn://tug.org/texlive/trunk@51473 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/support/fontools/README | 7 +- Master/texmf-dist/doc/support/fontools/splitttc | 271 ++++++++++++++++++++++++ 2 files changed, 276 insertions(+), 2 deletions(-) create mode 100755 Master/texmf-dist/doc/support/fontools/splitttc (limited to 'Master/texmf-dist/doc/support/fontools') diff --git a/Master/texmf-dist/doc/support/fontools/README b/Master/texmf-dist/doc/support/fontools/README index ebce4589825..4ceee70eff8 100644 --- a/Master/texmf-dist/doc/support/fontools/README +++ b/Master/texmf-dist/doc/support/fontools/README @@ -15,7 +15,10 @@ In addition, this bundle contains a few other, less important utilities: AFM2AFM - re-encode .afm files - OT2KPX - extract kerning pairs from OpenType fonts. + OT2KPX - extract kerning pairs from OpenType fonts + + SPLITTTC - split an OpenType Collection file (ttc or otc) into + individual fonts @@ -24,7 +27,7 @@ PREREQUISITES Perl - The Fontools are written in Perl; any version since v5.10.1 should work. + The Fontools are written in Perl; any remotely recent version should work. Perl is usually installed on Linux and Unix systems; for Windows, try ActivePerl (http://www.activestate.com) or Strawberry Perl (http://strawberryperl.com). diff --git a/Master/texmf-dist/doc/support/fontools/splitttc b/Master/texmf-dist/doc/support/fontools/splitttc new file mode 100755 index 00000000000..48d743b1dee --- /dev/null +++ b/Master/texmf-dist/doc/support/fontools/splitttc @@ -0,0 +1,271 @@ +#! /usr/bin/env perl + +=begin COPYRIGHT + +---------------------------------------------------------------------------- + + Copyright (C) 2019 Marc Penninga. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to + Free Software Foundation, Inc., + 59 Temple Place, + Suite 330, + Boston, MA 02111-1307, + USA + +---------------------------------------------------------------------------- + +=end COPYRIGHT + +=cut + +use strict; +use warnings; + +use File::Basename; +use Getopt::Long; +use Pod::Usage; + +my $VERSION = "20190625"; + +parse_commandline(); + +use constant { + SIZEOF_OFFSET_TABLE => 12, + SIZEOF_TABLE_RECORD => 16, +}; + +my $filename_in = $ARGV[0]; +my ($basename_out, undef, undef) = fileparse($filename_in, qw(.ttc .otc)); +my $output_prefix = $ARGV{output_prefix} // $basename_out; + +open my $fh, '<:raw', $filename_in + or die "[ERROR] cannot open $filename_in: $!"; +my $ttc = do { local $/; <$fh> }; +close $fh + or die "[ERROR] something went wrong when closing $filename_in: $!"; + +# unpack TTC header; we ignore the DSIG fields in version 2.0 headers +my ($ttc_tag, $major_version, $minor_version, $num_fonts) + = unpack 'A4 nnN', $ttc; +my $ttc_header_version = sprintf "%d.%d", $major_version, $minor_version; +die "$ARGV[0] is not an OpenType Collection file" if $ttc_tag ne 'ttcf'; +die "$ARGV[0]: unknown TTC Header Version $ttc_header_version" + if $ttc_header_version !~ m/\A [12] [.] 0 \z/xms; + +my $offsets_template = sprintf "\@%d N%d", SIZEOF_OFFSET_TABLE, $num_fonts; +my @offsets_of_offset_table = unpack $offsets_template, $ttc; + +# collect the data for each font and write to separate file +for my $i_font (1..$num_fonts) { + my $offset_of_offset_table = $offsets_of_offset_table[$i_font - 1]; + my $offset_table + = substr $ttc, $offset_of_offset_table, SIZEOF_OFFSET_TABLE; + + # unpack relevant fields from Offset Table + my ($sfnt_version, $num_tables) = unpack 'a4 n', $offset_table; + my $file_ext = $sfnt_version eq 'OTTO' ? 'otf' + : $sfnt_version eq "\x00\x01\x00\x00" ? 'ttf' + : die + ; + my $filename_out = sprintf "%s%d.%s", $output_prefix, $i_font, $file_ext; + + # unpack Table Records and create list of tables + my $table_records + = substr $ttc, + $offset_of_offset_table + SIZEOF_OFFSET_TABLE, + $num_tables * SIZEOF_TABLE_RECORD, + ; + my $table_records_template + = sprintf "(a%d)%d", SIZEOF_TABLE_RECORD, $num_tables; + my @table_records = unpack $table_records_template, $table_records; + for my $table_record (@table_records) { + my ($table_tag, $checksum, $offset, $length) + = unpack 'a4 N3', $table_record; + my $padding = "\x00" x ((4 - ($length % 4)) % 4); + my $table = substr($ttc, $offset, $length) . $padding; + $table_record = { + table_tag => $table_tag, + checksum => $checksum, + offset => $offset, + length => $length, + table => $table, + }; + } + + my $file_pos = SIZEOF_OFFSET_TABLE + length $table_records; + for my $table_record (@table_records) { + $table_record->{offset} = $file_pos; + $file_pos += length $table_record->{table}; + } + + open my $filehandle_out, '>:raw', $filename_out + or die "[ERROR] Cannot create $filename_out: $!"; + print {$filehandle_out} $offset_table; + for my $table_record (@table_records) { + print {$filehandle_out} + pack 'a4 N3', + @{$table_record}{ qw(table_tag checksum offset length) } + ; + } + for my $table_record (@table_records) { + print {$filehandle_out} $table_record->{table}; + } + close $filehandle_out + or die "[ERROR] something went wrong when closing $filename_out: $!"; +} + +#----------------------------------------------------------------------- +# Read the command-line options +#----------------------------------------------------------------------- +sub parse_commandline { + Getopt::Long::GetOptions( + 'help|?' => sub { pod2usage(-verbose => 1) }, + 'version' => sub { print "$VERSION\n"; exit }, + 'output-prefix=s' => \$ARGV{output_prefix}, + ) + or pod2usage(-verbose => 0); + + pod2usage(-verbose => 0) if @ARGV != 1; + + return; +} + + +__END__ + + +############################################################################ + + To create the documentation: + + pod2man --center="Marc Penninga" --release="fontools" --section=1 \ + splitttc - | groff -Tps -man - | ps2pdf - splitttc.pdf + +=pod + +=head1 NAME + +splitttc - split an OpenType Collection F or F file + +=head1 SYNOPSIS + +=over 8 + +=item B +[B<-help>] +[B<-version>] +[B<-output-prefix>=I<< >>] +B<< >> + +=back + + +=head1 DESCRIPTION + +B splits an OpenType Collection file. + +The OpenType specification allows for multiple fonts to be contained +in the same file. This might be advantageous if fonts share a lot of data, +as this then needs to be stored only once. Probably the best known +example of an OpenType Collection file is Microsoft's Cambria, +where the Regular weight shares a file with the Math font. + +Unfortunately some tools (including Eddie Kohler's LCDF TypeTools) +cannot handle such OpenType Collections; they only work for individual fonts. +B takes an OpenType Collection file +and splits it into its constituent parts. + +=head1 OPTIONS AND ARGUMENTS + +=over 4 + +=item B<-help> + +Print a short description of the syntax and exit. + +=item B<-version> + +Print version number and exit. + +=item B<-output-prefix>=I<< >> + +Write the individual fonts to files named I<< >>1.ttf, +I<< >>2.ttf etc. +The default is to take the prefix from the filename of the input file. + +=item B<< >> + +The F or F file to be split. + +=back + +You may use either one or two dashes before options, +and option names may be shortened to a unique prefix. + + +=head1 AUTHOR + +Marc Penninga + + +=head1 COPYRIGHT + +Copyright (C) 2019 Marc Penninga. + + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published +by the Free Software Foundation, either version 2 of the License, +or (at your option) any later version. +A copy of the GNU General Public License is included with B; +see the file F. + + +=head1 DISCLAIMER + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + + +=head1 VERSION + +This document describes B version 20190625. + + +=head1 RECENT CHANGES + +(See the source code for the rest of the story.) + +=over 12 + +=item I<2019-06-25> + +First release. + +=back + + +=begin Really_old_history + +=over 12 + +=back + +=cut + -- cgit v1.2.3