├── Resources ├── vmtx.AK12 ├── vmtx.AKR9 ├── vmtx.AC17 ├── vmtx.AG15 └── vmtx.AJ16 ├── LICENSE.md ├── unrange.pl ├── fix-fontbbox.pl ├── sfnt-collection-check.pl ├── mkvmtx.pl ├── mkrange.pl ├── mklocl.pl ├── subr-check.pl ├── glyph-list.pl ├── unicode-list.pl ├── fdarray-check.pl ├── proof.pl ├── hintcidfont.pl ├── setsnap.pl ├── mkicf.pl ├── unicode-rows.pl ├── README.md └── cmap-tool.pl /Resources/vmtx.AK12: -------------------------------------------------------------------------------- 1 | 141-145 2 | 208-216 3 | 258-264 4 | 266-269 5 | 279-324 6 | 328-356 7 | 451-518 8 | 587-678 9 | 757-772 10 | 1020-1085 11 | 8526-8577 12 | 8898-8949 13 | -------------------------------------------------------------------------------- /Resources/vmtx.AKR9: -------------------------------------------------------------------------------- 1 | 135-136 2 | 11491-11510 3 | 11704 4 | 11774-11777 5 | 11781 6 | 11787-11796 7 | 11803-11829 8 | 11836-11861 9 | 11866 10 | 11923-11925 11 | 11932-11951 12 | 12151-12232 13 | 12234 14 | -------------------------------------------------------------------------------- /Resources/vmtx.AC17: -------------------------------------------------------------------------------- 1 | 175 2 | 194 3 | 206 4 | 235-236 5 | 259-260 6 | 262-279 7 | 333-352 8 | 365-464 9 | 526-535 10 | 562-594 11 | 13930-13995 12 | 14009-14048 13 | 14054-14055 14 | 17601 15 | 18785-18843 16 | -------------------------------------------------------------------------------- /Resources/vmtx.AG15: -------------------------------------------------------------------------------- 1 | 165-172 2 | 190-239 3 | 250-261 4 | 265-267 5 | 277-286 6 | 293-319 7 | 326-351 8 | 525-572 9 | 602-699 10 | 9897-9906 11 | 9914-9915 12 | 10002-10012 13 | 10048 14 | 10056-10058 15 | 29064-30283 16 | -------------------------------------------------------------------------------- /Resources/vmtx.AJ16: -------------------------------------------------------------------------------- 1 | 710-720 2 | 758 3 | 771-772 4 | 780-841 5 | 1011-1124 6 | 7575-7584 7 | 7601-7607 8 | 7610-7612 9 | 8020-8037 10 | 8053 11 | 8055 12 | 8092-8101 13 | 8182 14 | 8186-8190 15 | 8192-8194 16 | 8225-8226 17 | 8295-8307 18 | 9779 19 | 9872-9883 20 | 11846-11870 21 | 12089-12096 22 | 16222 23 | 20427-20472 24 | 20919-20928 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2014-2019 Adobe. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /unrange.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This script uses STDIN and STDOUT, and simply unwinds a list of integer 8 | # or hexadecimal values, some of which may be expressed as ranges by 9 | # using a hyphen as a separator, into a single value per line. The "-h" 10 | # command-line option must be specified if the input is hexadecimal. 11 | # 12 | # Tool Dependencies: None 13 | 14 | $dohex = $len = 0; 15 | 16 | while ($ARGV[0]) { 17 | if ($ARGV[0] =~ /^-[hH]/) { 18 | $dohex = 1; 19 | shift; 20 | } else { 21 | print STDERR "Invalid option: $ARGV[0]! Skipping...\n"; 22 | shift; 23 | } 24 | } 25 | 26 | while(defined($line = )) { 27 | chomp $line; 28 | $line =~ s/\///g; 29 | if ($line =~ /-/) { 30 | ($begin,$end) = split(/-/,$line); 31 | if ($dohex) { 32 | $len = length $begin if not $len; 33 | foreach $num (hex($begin) .. hex($end)) { 34 | printf STDOUT "%0${len}X\n",$num; 35 | } 36 | } else { 37 | foreach $num ($begin .. $end) { 38 | print STDOUT "$num\n"; 39 | } 40 | } 41 | } else { 42 | print STDOUT "$line\n"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /fix-fontbbox.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This script takes a CIDFont resource as its only argument, and 8 | # outputs to STDOUT a CIDFont resource with a corrected /FontBBox 9 | # array. The original and corrected /FontBBox array values are output 10 | # to STDERR. 11 | # 12 | # Tool Dependencies: tx (AFDKO) 13 | 14 | $file = $ARGV[0]; 15 | 16 | # Set initial coordinates to the center of [0,-120,1000,880] 17 | 18 | $llx = $urx = 500; 19 | $lly = $ury = 380; 20 | 21 | # Create and open AFM file 22 | 23 | open(AFM,"tx -afm $file |") or die "Cannot open $file input file!\n"; 24 | 25 | while(defined($line = )) { 26 | chomp $line; 27 | if ($line =~ /FontBBox/) { 28 | ($bbox1) = $line =~ /FontBBox\s+(.+)/; 29 | } elsif ($line =~ /^C\s+.+;\s+N\s+.+\s+;\s+B\s+(.+)\s+;/) { 30 | ($a,$b,$c,$d) = split(/\s+/,$1); 31 | if ($a < $llx) { $llx = $a; } 32 | if ($b < $lly) { $lly = $b; } 33 | if ($c > $urx) { $urx = $c; } 34 | if ($d > $ury) { $ury = $d; } 35 | } 36 | } 37 | 38 | close(AFM); 39 | 40 | print STDERR "Original FontBBox: $bbox1\n"; 41 | print STDERR "Correct FontBBox: $llx $lly $urx $ury\n"; 42 | 43 | # Open CIDFont resource to change the /FontBBox array in its header 44 | 45 | open(FILE,"<$file") or die "Cannot open $file input file!\n"; 46 | 47 | while(defined($line = )) { 48 | if ($line =~ /\/FontBBox/) { 49 | $line = "/FontBBox {$llx $lly $urx $ury} def\n"; 50 | print STDERR "Corrected FontBBox\n"; 51 | } 52 | print STDOUT $line; 53 | } 54 | 55 | close(FILE); 56 | -------------------------------------------------------------------------------- /sfnt-collection-check.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-05-30 6 | # 7 | # This tool takes an 'sfnt' font collection, such as an OTC (OpenType/ 8 | # CFF Collection) or TTC (TrueType Collection), as its only command- 9 | # line argument, then lists the number of fonts (as determined by the 10 | # number of 'name' table instances), a listing of which tables are 11 | # completely unshared, partially shared, and completely shared, along 12 | # with a list of each table and the number of their instances, sorted 13 | # from highest to lowest. 14 | # 15 | # Tool Dependencies: spot (AFDKO) 16 | 17 | $unshared = $partially_shared = $shared = ""; 18 | 19 | $file = $ARGV[0]; 20 | open(FILE,"spot -T $file |") or die "Cannot open $file!\n"; 21 | 22 | while(defined($line = )) { 23 | chomp $line; 24 | if ($line =~ /\'(....)\'((?:,[0-9a-f]{8}){3})}/) { 25 | $data->{$1}{$2} = 1; 26 | } 27 | } 28 | 29 | $fonts = scalar keys %{ $data->{name} }; 30 | 31 | foreach $table (sort {$a cmp $b} keys %{ $data }) { 32 | if (scalar keys %{ $data->{$table} } == 1) { 33 | if (not $shared) { 34 | $shared = $table; 35 | } else { 36 | $shared .= ", " . $table; 37 | } 38 | } elsif (scalar keys %{ $data->{$table} } == $fonts) { 39 | if (not $unshared) { 40 | $unshared = $table; 41 | } else { 42 | $unshared .= ", " . $table; 43 | } 44 | } else { 45 | if (not $partially_shared) { 46 | $partially_shared = $table; 47 | } else { 48 | $partially_shared .= ", " . $table; 49 | } 50 | } 51 | } 52 | 53 | print STDOUT "Number of Fonts: $fonts\n"; 54 | print STDOUT "Completely Unshared Tables: $unshared\n"; 55 | print STDOUT "Partially Shared Tables: $partially_shared\n"; 56 | print STDOUT "Completely Shared Tables: $shared\n"; 57 | 58 | foreach $table (sort { scalar keys %{ $data->{$b} } <=> scalar keys %{ $data->{$a} } or $a cmp $b } keys %{ $data }) { 59 | $count = scalar keys %{ $data->{$table} }; 60 | print STDOUT "$table = $count\n"; 61 | } 62 | -------------------------------------------------------------------------------- /mkvmtx.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This tool takes a CIDFont resource as its only command-line argument, 8 | # along with a list of CIDs or CID ranges that correspond to full-width 9 | # glyphs that rest on the Western baseline, such as Latin, Greek, 10 | # Cyrillic, currency symbols, and other characters, as STDIN, and 11 | # generates a 'vmtx' table override that can be included in a "features" 12 | # file. The glyphs are mechanically centered along the Y-axis by using 13 | # the top and bottom of the em-box as reference points, along with the 14 | # top and bottom of their bounding boxes. 15 | # 16 | # Tool Dependencies: tx (AFDKO) 17 | 18 | $file = $ARGV[0]; 19 | open(AFM,"tx -afm $file |") or die "Cannot open $file input file!\n"; 20 | 21 | $count = 0; 22 | 23 | print STDERR "Loading CIDs ..."; 24 | 25 | while ($line = ) { 26 | chomp $line; 27 | $count++; 28 | $line =~ s/^\s*(.*)\s*$/$1/; 29 | $line =~ s/\s+/ /; 30 | 31 | if ($line =~ /-/) { 32 | ($cidstart,$cidend) = split /-/, $line; 33 | } else { 34 | $cidstart = $line; 35 | $cidend = $cidstart; 36 | } 37 | foreach $cid ($cidstart .. $cidend) { 38 | $cidrange{$cid} = 1; 39 | } 40 | } 41 | 42 | print STDERR "Done\n"; 43 | 44 | # Adjust the values of the variables $ybottomlimit and $ytoplimit to 45 | # correspond to the bottom and top of the em-box. 46 | 47 | $ybottomlimit = -120; 48 | $ytoplimit = 880; 49 | 50 | $ycenter = ($ybottomlimit + $ytoplimit) / 2; 51 | 52 | # Generate the 'vmtx' table override by mechanically-centering the 53 | # specified CIDs along the Y-axis according to the em-box and glyph 54 | # bounding boxes. 55 | 56 | print STDOUT "table vmtx {\n"; 57 | 58 | while ($line = ) { 59 | if ($line =~ /^C.*/) { 60 | chomp $line; 61 | ($cid,$ymin,$ymax) = (split(/ /,$line))[7,11,13]; 62 | if (exists $cidrange{$cid}) { 63 | $halfy = ($ymax - $ymin) / 2; 64 | $yminnew = $ycenter - $halfy; 65 | $pushy = round($yminnew - $ymin); 66 | $pushy =~ s/^\+(\d+)/$1/; 67 | printf STDOUT " VertOriginY \\$cid %s;\n",$ytoplimit - $pushy if $pushy !~ /^-?[0-4]$/; 68 | } 69 | } 70 | } 71 | 72 | print STDOUT "} vmtx;\n"; 73 | 74 | sub round { 75 | my ($arg) = @_; 76 | if ($arg =~ /\.[0-4]\d*/) { 77 | $arg =~ s/\.[0-4]\d*$//; 78 | } elsif ($arg =~ /\.[5-9]\d*/) { 79 | $arg =~ s/(\d+)\.[5-9]\d*$/$1 + 1/e; 80 | } return $arg; 81 | } 82 | -------------------------------------------------------------------------------- /mkrange.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This script takes a list of integer values as STDIN and outputs to 8 | # STDOUT the same list, but as ranges of contiguous integer values 9 | # using a hyphen as the separator. No sorting is performed, and the 10 | # integer values can be prefixed with a slash (the use of a slash 11 | # prefix explicitly specifies CID values, as opposed to GID values, 12 | # which is useful for CID-keyed font development). Hexadecimal values 13 | # are supported if the "-h" command-line option is specified. 14 | # 15 | # The "-s" command-line option will output the single values and 16 | # ranges as a single line that uses a comma as a separator. 17 | # 18 | # Tool Dependencies: None 19 | 20 | $second = $dohex = 0; 21 | $prefix = ""; 22 | $sep = "\n"; 23 | 24 | while ($ARGV[0]) { 25 | if ($ARGV[0] =~ /^-[sS]/) { 26 | $sep = ","; 27 | shift; 28 | } elsif ($ARGV[0] =~ /^-[hH]/) { 29 | $dohex = 1; 30 | shift; 31 | } else { 32 | print STDERR "Invalid option: $ARGV[0]! Skipping...\n"; 33 | shift; 34 | } 35 | } 36 | 37 | 38 | while(defined($line = )) { 39 | chomp $line; 40 | if ($line =~ m#^/#) { 41 | $line =~ s#^/##; 42 | $prefix = "/"; 43 | } 44 | if (not $second) { 45 | $orig = $previous = $line; 46 | $second = 1; 47 | next; 48 | } 49 | if ($dohex) { 50 | if (hex($line) != hex($previous) + 1) { 51 | if ($orig eq $previous) { 52 | print STDOUT $prefix . $orig . $sep; 53 | } else { 54 | print STDOUT $prefix . $orig . "-" . $prefix . $previous . $sep; 55 | } 56 | $orig = $previous = $line; 57 | } else { 58 | $previous = $line; 59 | } 60 | } else { 61 | if ($line != $previous + 1) { 62 | if ($orig == $previous) { 63 | print STDOUT $prefix . $orig . $sep; 64 | } else { 65 | print STDOUT $prefix . $orig . "-" . $prefix . $previous . $sep; 66 | } 67 | $orig = $previous = $line; 68 | } else { 69 | $previous = $line; 70 | } 71 | } 72 | } 73 | 74 | if ($dohex) { 75 | if ($orig eq $previous) { 76 | print STDOUT $prefix . $orig . "\n"; 77 | } else { 78 | print STDOUT $prefix . $orig . "-" . $prefix . $previous . "\n"; 79 | } 80 | } else { 81 | if ($orig == $previous) { 82 | print STDOUT $prefix . $orig . "\n"; 83 | } else { 84 | print STDOUT $prefix . $orig . "-" . $prefix . $previous . "\n"; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /mklocl.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This tool is useful for Pan-CJK font development in that it 8 | # synthesizes a lookup for the 'locl' (Localized Forms) GSUB feature 9 | # by specifying two region or language identifiers, whereby the input 10 | # one is considered the default region or language in terms of which 11 | # glyphs are encoded by default, and the output one is a non-default 12 | # region or language. Only those code points whose CIDs are different 13 | # for the two specified regions or languages are included in the 14 | # lookup declaration. The input and output files, whose lines 15 | # individually map eight-digit UTF-32 character codes to CIDs, and 16 | # whose names must follow the pattern "utf32-.map," serve 17 | # as the arguments of the "-i" and "-o" command-line options, 18 | # respectively, and the region or language identifiers are used for 19 | # the names of the lookup declarations. 20 | 21 | # Tool Dependencies: None 22 | 23 | while ($ARGV[0]) { 24 | if ($ARGV[0] =~ /^-[huHU]/) { 25 | print STDERR "Usage: mklocl.pl -i -o > \n"; 26 | exit; 27 | } elsif ($ARGV[0] =~ /^-[iI]/) { 28 | shift; 29 | $input = $ARGV[0]; 30 | shift; 31 | } elsif ($ARGV[0] =~ /^-[oO]/) { 32 | shift; 33 | $output = $ARGV[0]; 34 | shift; 35 | } 36 | } 37 | 38 | # Extract the region or language identifiers from the input and output 39 | # file names, which are used for the name of the lookup declaration 40 | 41 | ($input_locl) = $input =~ /utf32-(.+)\.map/; 42 | ($output_locl) = $output =~ /utf32-(.+)\.map/; 43 | 44 | open(INPUT,"<$input") or die "Error opening $input mapping file.\n"; 45 | open(OUTPUT,"<$output") or die "Error opening $output mapping file.\n"; 46 | 47 | # Store the input mappings 48 | 49 | while(defined($line = )) { 50 | chomp $line; 51 | ($uni,$cid) = $line =~ /^<([0-9A-F]{8})>\s+(\d+)$/; 52 | $mapping{$uni} = $cid; 53 | } 54 | 55 | # Compare the output mappings to the stored input mappings, and 56 | # store any differences in the %cid2cid hash 57 | 58 | while(defined($line = )) { 59 | chomp $line; 60 | ($uni,$cid) = $line =~ /^<([0-9A-F]{8})>\s+(\d+)$/; 61 | if ($mapping{$uni} != $cid) { 62 | $cid2cid{ $mapping{$uni} } = $cid; 63 | } 64 | } 65 | 66 | # Synthesize the lookup by using the %cid2cid hash 67 | 68 | print STDOUT "lookup ${input_locl}2${output_locl} useExtension {\n"; 69 | 70 | foreach $cid (sort {$a <=> $b} keys %cid2cid) { 71 | print STDOUT " substitute \\$cid by \\$cid2cid{$cid};\n"; 72 | } 73 | 74 | print STDOUT "} ${input_locl}2${output_locl};\n\n"; 75 | -------------------------------------------------------------------------------- /subr-check.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This tool takes a CFF resource/table (instantiated as a file) or an 8 | # OpenType/CFF (name- or CID-keyed) as its only argument, and reports 9 | # the number of global (for name- and CID-keyed fonts) and local (for 10 | # CID-keyed fonts only) subroutines are present, their sizes in bytes, 11 | # and whether the number of subroutines exceeds architectural (64K - 3 12 | # = 65,533) or known implementation-specific (32K - 3 = 32,765) 13 | # limits. 14 | # 15 | # Mac OS X Version 10.4 (aka, Tiger) and earlier, along with Adobe 16 | # Acrobat Distiller Version 7.0 and earlier, are known implementations 17 | # whose subroutine limit is 32K - 3 (32,765). 18 | # 19 | # Tool Dependencies: tx (AFDKO) 20 | 21 | if ($ARGV[0] =~ /^-[huHU]/) { 22 | print STDERR "Usage: subr-check.pl \n"; 23 | exit; 24 | } else { 25 | $file = "\"$ARGV[0]\""; 26 | } 27 | 28 | $fd = "global"; 29 | 30 | # Extract the number of global and local subroutines, and store in hash 31 | 32 | open(FILE,"tx -dcf -1 -T gl $file |") or die "Cannot open $file input file!\n"; 33 | 34 | while(defined($line = )) { 35 | next if $line !~ /^(?:---\sFD|count)/; 36 | if ($line =~ /^count\s+=(\d+)/) { 37 | $data->{$fd} = $1; 38 | } elsif ($line =~ /^---\sFD\[(\d+)\]/) { 39 | $fd = $1; 40 | } 41 | } 42 | close(FILE); 43 | 44 | $fd = "global"; 45 | 46 | # Extract the sizes of the global and local subroutines, and store in hash 47 | 48 | open(FILE,"tx -dcf -0 -T gl $file |") or die "Cannot open $file input file!\n"; 49 | 50 | while(defined($line = )) { 51 | next if $line !~ /^(?:---\sFD|###)/; 52 | if ($line =~ /^### (?:Global|Local).+\(([0-9a-f]{8})-([0-9a-f]{8})\)/) { 53 | $size->{$fd} = hex($2) - hex($1) + 1; 54 | } elsif ($line =~ /^---\sFD\[(\d+)\]/) { 55 | $fd = $1; 56 | } 57 | } 58 | close(FILE); 59 | 60 | printf STDOUT "Global Subroutines: %d (%d bytes)",$data->{"global"},$size->{"global"}; 61 | 62 | $totalsize = $size->{"global"}; 63 | 64 | if ($data->{"global"} > 65533) { 65 | print STDOUT " > 64K-3 limit"; 66 | } elsif ($data->{"global"} > 32765) { 67 | print STDOUT " > 32K-3 limit"; 68 | } 69 | 70 | print STDOUT "\nLocal Subroutines:"; 71 | 72 | if (scalar keys %{ $data } == 1) { 73 | print STDOUT " 0\n"; 74 | } else { 75 | print STDOUT "\n"; 76 | foreach $index (sort {$a <=> $b} keys %{ $data }) { 77 | next if $index eq "global"; 78 | printf STDOUT " FD=${index}: %d (%d bytes)",$data->{$index},$size->{$index}; 79 | $totalsize += $size->{$index}; 80 | if ($data->{$index} + $data->{"global"} > 65533) { 81 | printf STDOUT " > 64K-3 limit: %d (%d + %d)",$data->{$index} + $data->{"global"},$data->{$index},$data->{"global"}; 82 | } elsif ($data->{$index} + $data->{"global"} > 32765) { 83 | printf STDOUT " > 32K-3 limit: %d (%d + %d)",$data->{$index} + $data->{"global"},$data->{$index},$data->{"global"}; 84 | } 85 | print STDOUT "\n"; 86 | } 87 | } 88 | 89 | print STDOUT "Total Subroutine Size: $totalsize bytes\n"; 90 | -------------------------------------------------------------------------------- /glyph-list.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This tool lists the glyphs in the specified font, which can be a 8 | # CIDFont resource, a name-keyed Type 1 font (PFA), or an 'sfnt' 9 | # (TrueType or OpenType) font. By default, glyphs are listed as CIDs 10 | # or glyph names, depending on whether the font is CID- or name-keyed. 11 | # CIDs are prefixed with a slash. The "-g" command-line option will 12 | # list GIDs in lieu of CIDs or glyph names. The "-r" command-line 13 | # option will turn the list of CIDs or GIDs into ranges. The "-s" 14 | # command-line option will additionally output lists or ranges onto 15 | # a single line with comma separators so that it can be repurposed, such 16 | # as to be used as the argument of the "-g" or "-gx" command-line 17 | # options that are supported by many AFDKO tools. 18 | # 19 | # Tool Dependencies: tx (AFDKO) 20 | 21 | $usegid = $second = $range = 0; 22 | $iscid = 1; 23 | $sep = "\n"; 24 | $prefix = "/"; 25 | $data = ""; 26 | 27 | while ($ARGV[0]) { 28 | if ($ARGV[0] =~ /^-[huHU]/) { 29 | print STDERR "Usage: glyph-list.pl [-g] [-r] [-s] \n"; 30 | exit; 31 | } elsif ($ARGV[0] =~ /^-[gG]/) { 32 | $usegid = 1; 33 | $prefix = ""; 34 | shift; 35 | } elsif ($ARGV[0] =~ /^-[rR]/) { 36 | $range = 1; 37 | shift; 38 | } elsif ($ARGV[0] =~ /^-[sS]/) { 39 | $sep = ","; 40 | shift; 41 | } else { 42 | $file = "\"$ARGV[0]\""; 43 | shift; 44 | } 45 | } 46 | 47 | open(FILE,"tx -1 $file |") or die "Cannot open $file input file!\n"; 48 | 49 | while(defined($line = )) { 50 | chomp $line; 51 | if ($line =~ /^sup\.srcFontType/) { 52 | if ($line =~ /(?:TrueType|name-keyed)/) { 53 | $iscid = 0; 54 | $range = 0 if not $usegid; 55 | $prefix = ""; 56 | } 57 | next; 58 | } 59 | next if $line !~ /glyph\[\d+\]/; 60 | if ($usegid) { 61 | ($glyph) = $line =~ /glyph\[(\d+)\]/; 62 | } else { 63 | ($glyph) = $line =~ /{(.+?),/; 64 | } 65 | if ($range) { 66 | if (not $second) { 67 | $orig = $previous = $glyph; 68 | $second = 1; 69 | next; 70 | } 71 | if ($glyph != $previous + 1) { 72 | if ($orig == $previous) { 73 | $data .= "$prefix$orig$sep"; 74 | } else { 75 | $data .= "$prefix$orig-$prefix$previous$sep"; 76 | } 77 | $orig = $previous = $glyph; 78 | } else { 79 | $previous = $glyph; 80 | } 81 | } else { 82 | if (not $sep) { 83 | $data .= "$prefix$glyph\n"; 84 | } else { 85 | if (not $data) { 86 | $data .= "$prefix$glyph"; 87 | } else { 88 | $data .= "$sep$prefix$glyph"; 89 | } 90 | } 91 | } 92 | } 93 | 94 | if ($range) { 95 | if ($orig == $previous) { 96 | $data .= "$prefix$orig\n"; 97 | } else { 98 | $data .= "$prefix$orig-$prefix$previous\n"; 99 | } 100 | } else { 101 | $data .= "\n"; 102 | } 103 | 104 | print STDOUT $data; 105 | -------------------------------------------------------------------------------- /unicode-list.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This tool lists the Unicode code points in the specified OpenType 8 | # font. By default, only the Unicode code points are listed, one per 9 | # line, and if the OpenType font includes both a Format 4 (BMP-only 10 | # UTF-16) and Format 12 (UTF-32) 'cmap' subtable, the latter is used. 11 | # 12 | # The "-g" command-line option will include the glyph names (for name- 13 | # keyed fonts) or CIDs (for CID-keyed fonts) in a second column. 14 | # 15 | # The "-r" command-line option will turn the list of Unicode code 16 | # points into ranges. 17 | # 18 | # If both command-line options are specified, the "-r" command-line 19 | # option is ignored. 20 | # 21 | # Tool Dependencies: spot (AFDKO) 22 | 23 | $addglyph = $range = $second = 0; 24 | $data = ""; 25 | 26 | while ($ARGV[0]) { 27 | if ($ARGV[0] =~ /^-[huHU]/) { 28 | print STDERR "Usage: unicode-list.pl [-g|-r] \n"; 29 | exit; 30 | } elsif ($ARGV[0] =~ /^-[gG]/) { 31 | $addglyph = 1; 32 | shift; 33 | } elsif ($ARGV[0] =~ /^-[rR]/) { 34 | $range = 1; 35 | shift; 36 | } else { 37 | $file = "\"$ARGV[0]\""; 38 | shift; 39 | } 40 | } 41 | 42 | $range = 0 if $addglyph; 43 | 44 | open(FILE,"spot -tcmap=11 $file |") or die "Cannot open $file input file!\n"; 45 | 46 | while(defined($line = )) { 47 | chomp $line; 48 | if ($line =~ /=/) { 49 | if ($line =~ /^\[\s*(\d+)\]={.+(?:UTF-(16|32)).+}$/) { 50 | if ($2 == 16) { 51 | $utf16 = $1; 52 | } elsif ($2 == 32) { 53 | $utf32 = $1; 54 | } 55 | } elsif ($line =~ /^\[\s*(\d+)\]={Microsoft,Unicode\s(BMP|UCS[-]4).+}$/) { 56 | if ($2 eq "BMP") { 57 | $utf16 = $1; 58 | } elsif ($2 eq "UCS-4") { 59 | $utf32 = $1; 60 | } 61 | } 62 | } 63 | } 64 | close(FILE); 65 | 66 | if (defined $utf32) { 67 | $index = $utf32; 68 | undef $utf16; 69 | } else { 70 | $index = $utf16; 71 | } 72 | 73 | open(FILE,"spot -tcmap=7 -C$index $file |") or die "Cannot open $file input file!\n"; 74 | 75 | while(defined($line = )) { 76 | chomp $line; 77 | if ($line =~ /^\[([0-9A-F]+)\]=<\\?(.+)>/) { 78 | $uni = $1; 79 | $glyph = $2; 80 | 81 | if ($range) { 82 | if (not $second) { 83 | $orig = $previous = $uni; 84 | $second = 1; 85 | next; 86 | } 87 | if (hex($uni) != hex($previous) + 1) { 88 | if ($orig eq $previous) { 89 | $data .= "$orig\n"; 90 | } else { 91 | $data .= "$orig-$previous\n"; 92 | } 93 | $orig = $previous = $uni; 94 | } else { 95 | $previous = $uni; 96 | } 97 | } elsif ($addglyph) { 98 | $data .= "$uni\t$glyph\n"; 99 | } else { 100 | $data .= "$uni\n"; 101 | } 102 | } 103 | } 104 | 105 | if ($range) { 106 | if ($orig eq $previous) { 107 | $data .= "$orig\n"; 108 | } else { 109 | $data .= "$orig-$previous\n"; 110 | } 111 | } 112 | 113 | print STDOUT $data; 114 | -------------------------------------------------------------------------------- /fdarray-check.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This tool takes a CID-keyed font, which can be a CIDFont resource 8 | # (instantiated as a file), CFF resource/table (instantiated as a 9 | # file), or an OpenType/CFF font, as its only argument, and reports 10 | # to STDOUT the name of each FDArray element, along with its index in 11 | # parentheses, the CIDs that are assigned to it, and the total number 12 | # of CIDs in parentheses. The CIDs are prefixed with a slash to 13 | # explicitly indicate CIDs, as opposed to GIDs, which is useful when 14 | # using the "-g" or "-gx" command-line options for many AFDKO tools, 15 | # especially when GIDs do not equal CIDs in a particular font. The 16 | # slash prefix can be suppressed by specifying the "-g" command-line 17 | # option, and the values are still CIDs, not GIDs. The ROS (/Registry, 18 | # /Ordering, and /Supplement) of the CID-keyed font is also reported 19 | # to STDOUT. This tool also reports, via STDERR, whether GIDs do not 20 | # equal CIDs in the specified font, and starting from which GID/CID. 21 | # 22 | # Tool Dependencies: tx (AFDKO) 23 | 24 | $pre = "/"; 25 | $gidNEcid = 0; 26 | 27 | while ($ARGV[0]) { 28 | if ($ARGV[0] =~ /^-[huHU]/) { 29 | print STDERR "Usage: fdarray-check.pl [-g] \n"; 30 | exit; 31 | } elsif ($ARGV[0] =~ /^-[gG]/) { 32 | $pre = ""; 33 | shift; 34 | } else { 35 | $file = "\"$ARGV[0]\""; 36 | shift; 37 | } 38 | } 39 | 40 | open(FILE,"tx -1 $file |") or die "Cannot open $file input file!\n"; 41 | 42 | while(defined($line = )) { 43 | chomp $line; 44 | if ($line =~ /^cid\.Registry\s+\"(.+)\"/) { 45 | $r = $1; 46 | } elsif ($line =~ /^cid\.Ordering\s+\"(.+)\"/) { 47 | $o = $1; 48 | } elsif ($line =~ /^cid\.Supplement\s+(\d+)/) { 49 | $s = $1; 50 | } elsif ($line =~ /^## FontDict\[(\d+)\]/) { 51 | $index = $1; 52 | } elsif ($line =~ /^FontName\s+\"(.+)\"/) { 53 | $fdarray->{$index}{NAME} = $1; 54 | } elsif ($line =~ /^glyph\[(\d+)\]\s+{(\d+),(\d+)(?:,[01])?}/) { 55 | $gid = $1; 56 | $cid = $2; 57 | $index = $3; 58 | if (not exists $fdarray->{$index}{CIDs}) { 59 | $fdarray->{$index}{CIDs} = $cid; 60 | } else { 61 | $fdarray->{$index}{CIDs} .= "," . $cid; 62 | } 63 | if (not $gidNEcid and $gid != $cid) { 64 | $gidNEcid = 1; 65 | print STDERR "NOTE: GIDs do not equal CIDs starting from GID+$gid/CID+$cid!\n"; 66 | } 67 | } elsif ($line =~ /^glyph\[\d+\]\s+{[^0-9].*,/) { 68 | die "ERROR: name-keyed font! Quitting...\n"; 69 | } 70 | } 71 | 72 | print STDOUT "Detected ROS: $r-$o-$s\n"; 73 | 74 | foreach $element (sort {$a <=> $b} keys %{ $fdarray }) { 75 | printf STDOUT "%s ($element): ",$fdarray->{$element}{NAME}; 76 | @cids = split(/,/,$fdarray->{$element}{CIDs}); 77 | $count = scalar @cids; 78 | $second = 0; 79 | foreach $cid (@cids) { 80 | if (not $second) { 81 | $orig = $previous = $cid; 82 | $second = 1; 83 | next; 84 | } 85 | if ($cid != $previous + 1) { 86 | if ($orig == $previous) { 87 | print STDOUT "$pre$orig,"; 88 | } else { 89 | print STDOUT "$pre$orig-$pre$previous,"; 90 | } 91 | $orig = $previous = $cid; 92 | } else { 93 | $previous = $cid; 94 | } 95 | } 96 | if ($orig == $previous) { 97 | print STDOUT "$pre$orig"; 98 | } else { 99 | print STDOUT "$pre$orig-$pre$previous"; 100 | } 101 | print STDOUT " ($count)\n"; 102 | } 103 | -------------------------------------------------------------------------------- /proof.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # This script accepts as STDIN a list of CIDs (for CIDFont resources), 8 | # glyph names (for name-keyed fonts), or eight-digit hexadecimal 9 | # UTF-32 character codes (for CID-keyed fonts that specify a UTF-32 10 | # CMap resource). For glyph names, the "-t1" command-line option must 11 | # be specified, and for eight-digit hexadecimal UTF-32 character 12 | # codes, the "-uni" command-line option must be used. 13 | # 14 | # This script outputs to STDOUT a PostScript file that is expected to 15 | # serve as input to the Distiller app to create a PDF file for 16 | # proofing a font against a known or "template" font. Each specified 17 | # glyph, in the template and proofing font, is shown twice. The first 18 | # instance is in the second and third columns in black, overlaid by 19 | # the other glyph in gray. The second instance is in the fourth and 20 | # fifth columns in black. The specified template and proofing font 21 | # resources must be accessible to the Distiller app, and if a 22 | # full-qualified PostScript font name is specified for CID-keyed 23 | # fonts, the (UTF-32) CMap resource must also be accessible. Font 24 | # resources must have the appropriate embedding permissions set, and 25 | # for CIDFont resources, this means that the /FontInfo dictionary must 26 | # include /FSType with a value of 0, 4, or 8. 27 | # 28 | # Tool Dependencies: Adobe Acrobat Distiller 29 | # Font Dependencies: Courier 30 | 31 | $do_uni = $do_t1 = 0; 32 | 33 | print STDOUT "\%!\n\n"; 34 | print STDOUT "/C { /Courier findfont 20 scalefont setfont } bind def\n"; 35 | print STDOUT "/G { 0.75 setgray } bind def /UG { 0.0 setgray } bind def\n"; 36 | 37 | @glyphs = ; 38 | chomp @glyphs; 39 | 40 | while ($ARGV[0]) { 41 | if ($ARGV[0] =~ /^-t1$/) { 42 | $do_t1 = 1; 43 | shift; 44 | } elsif ($ARGV[0] =~ /^-uni$/) { 45 | $do_uni = 1; 46 | shift; 47 | } else { 48 | $tf = "/" . $ARGV[0]; 49 | shift; 50 | $pf = "/" . $ARGV[0]; 51 | shift; 52 | } 53 | } 54 | 55 | if ($do_t1 or $do_uni) { 56 | print STDOUT "/TF { $tf findfont 95 scalefont setfont } bind def\n"; 57 | print STDOUT "/PF { $pf findfont 95 scalefont setfont } bind def\n"; 58 | if ($do_t1) { 59 | foreach $glyph (@glyphs) { 60 | $glyph = "/" . $glyph; 61 | } 62 | } 63 | } else { 64 | print STDOUT "/TF { $tf /CIDFont findresource 95 scalefont setfont } bind def\n"; 65 | print STDOUT "/PF { $pf /CIDFont findresource 95 scalefont setfont } bind def\n"; 66 | foreach $glyph (@glyphs) { 67 | if ($glyph =~ /[-]/) { 68 | $glyph =~ s#/##g; 69 | ($begin,$end) = split(/[-]/,$glyph); 70 | foreach $cid ($begin .. $end) { 71 | $allglyphs{$cid} = 1; 72 | } 73 | } else { 74 | $glyph =~ s#^/##; 75 | $allglyphs{$glyph} = 1; 76 | } 77 | } 78 | @glyphs = sort {$a <=> $b} keys %allglyphs; 79 | } 80 | 81 | $y = 700; 82 | print STDOUT "\n"; 83 | 84 | foreach $glyph (@glyphs) { 85 | if ($do_uni) { 86 | $tempglyph = sprintf("U+%04X",hex $glyph); 87 | print STDOUT < show 300 $y moveto PF <$glyph> show 400 $y moveto TF <$glyph> show 500 $y moveto PF <$glyph> show G 200 $y moveto <$glyph> show 300 $y moveto TF <$glyph> show UG 89 | EOF 90 | 91 | } else { 92 | print STDOUT <)) { 28 | chomp $line; 29 | if ($line =~ /^([A-Z][A-Za-z0-9]?.+)$/) { 30 | $hintdictname1 = $1; 31 | } elsif ($line =~ /(\/(?:BlueValues|BlueScale|OtherBlues|Std(?:H|V)W|StemSnap(?:H|V))\s+\[?\s*.+\s*\]?\s+def)/) { 32 | $hintdata{$hintdictname1} .= $1 . "\n"; 33 | } 34 | } 35 | 36 | while(defined($line = )) { 37 | if ($line =~ /\/CIDFontName\s+\/(.+)\s+def/) { 38 | $cidfontname = $1; 39 | print STDERR "Detected CIDFontName: $cidfontname\n"; 40 | } elsif ($line =~ /\/FontName \/${cidfontname}-(.+)\s+def/) { 41 | $hintdictname2 = $1; 42 | print STDERR "Modifying $hintdictname2 hinting parameters...\n"; 43 | } elsif ($line =~ /\/Private \d+ dict dup begin/) { 44 | print STDOUT "/Private 15 dict dup begin\n"; 45 | print STDOUT $hintdata{$hintdictname2}; 46 | next; 47 | } elsif ($line =~/\/(?:Blue(?:Values|Scale|Fuzz)|(?:Family)?(?:Other)?Blues|Std(?:H|V)W|StemSnap(?:H|V)|RndStemUp)/ && exists $hintdata{$hintdictname2}) { 48 | next; 49 | } 50 | print STDOUT $line; 51 | } 52 | 53 | __END__ 54 | Alphabetic 55 | /BlueValues [-13 0 526 540 726 739] def 56 | /OtherBlues [-256 -243] def 57 | /StdHW [33] def 58 | /StdVW [37] def 59 | 60 | AlphabeticDigits 61 | /BlueValues [-14 0 704 716 726 738] def 62 | /StdHW [34] def 63 | /StdVW [38] def 64 | 65 | Bopomofo 66 | /BlueValues [-250 -250 1100 1100] def 67 | /StdHW [22] def 68 | /StdVW [22] def 69 | 70 | Dingbats 71 | /BlueValues [-1100 -1100 1900 1900] def 72 | /StdHW [30] def 73 | /StdVW [30] def 74 | /StemSnapH [14 30] def 75 | /StemSnapV [30 41] def 76 | 77 | DingbatsDigits 78 | /BlueValues [0 0 523 523 721 721] def 79 | /StdHW [40] def 80 | /StdVW [40] def 81 | 82 | Generic 83 | /BlueValues [-250 -250 1100 1100] def 84 | /StdHW [40] def 85 | /StdVW [40] def 86 | /StemSnapH [40 120] def 87 | /StemSnapV [40 120] def 88 | 89 | HDingbats 90 | /BlueValues [-250 -250 1100 1100] def 91 | /StdHW [35] def 92 | /StdVW [35] def 93 | 94 | HHangul 95 | /BlueValues [-250 -250 1100 1100] def 96 | /StdHW [27] def 97 | /StdVW [30] def 98 | 99 | HKana 100 | /BlueValues [-250 -250 1100 1100] def 101 | /StdHW [30] def 102 | /StdVW [30] def 103 | 104 | HWidth 105 | /BlueValues [-14 0 526 539 726 738] def 106 | /OtherBlues [-236 -224] def 107 | /StdHW [31] def 108 | /StdVW [30] def 109 | /StemSnapH [31 80] def 110 | /StemSnapV [30 80] def 111 | 112 | HWidthCJK 113 | /BlueValues [-250 -250 1100 1100] def 114 | /StdHW [31] def 115 | /StdVW [30] def 116 | 117 | HWidthDigits 118 | /BlueValues [-12 0 704 717] def 119 | /StdHW [26] def 120 | /StdVW [36] def 121 | /StemSnapH [26 34] def 122 | 123 | Hangul 124 | /BlueValues [-250 -250 1100 1100] def 125 | /StdHW [30] def 126 | /StdVW [33] def 127 | 128 | Ideographs 129 | /BlueValues [-250 -250 1100 1100] def 130 | /StdHW [29] def 131 | /StdVW [29] def 132 | 133 | Kana 134 | /BlueValues [-250 -250 1100 1100] def 135 | /StdHW [30] def 136 | /StdVW [30] def 137 | 138 | Proportional 139 | /BlueValues [-13 0 527 540 726 739] def 140 | /OtherBlues [-257 -243 -210 -210] def 141 | /StdHW [33] def 142 | /StdVW [30] def 143 | /StemSnapV [30 37] def 144 | 145 | ProportionalCJK 146 | /BlueValues [-250 -250 1100 1100] def 147 | /StdHW [25] def 148 | /StdVW [34] def 149 | /StemSnapH [25 75 88] def 150 | /StemSnapV [34 81] def 151 | 152 | ProportionalDigits 153 | /BlueValues [-13 0 726 740] def 154 | /StdHW [26] def 155 | /StdVW [35] def 156 | 157 | VKana 158 | /BlueValues [-250 -250 1100 1100] def 159 | /StdHW [30] def 160 | /StdVW [30] def 161 | -------------------------------------------------------------------------------- /setsnap.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # Written by Dr. Ken Lunde (lunde@adobe.com) 4 | # Senior Computer Scientist 2, Adobe Inc. 5 | # Version 2019-03-27 6 | # 7 | # Please invoke this script using the "-u" command-line option to see 8 | # the command-line options, or "-h" to display more information. 9 | # 10 | # Tool Dependencies: None 11 | 12 | $makefile = $number = $optimize = $hicount = $hiwidth = 0; 13 | $newline = "\n"; 14 | $bottom = 9; 15 | $top = 24; 16 | $res = 72; 17 | 18 | while (@ARGV and $ARGV[0] =~ /^-/) { 19 | my $arg = shift @ARGV; 20 | if (lc $arg eq "-u") { 21 | &ShowUsage; 22 | exit; 23 | } elsif (lc $arg eq "-h") { 24 | &ShowUsage; 25 | &ShowHelp; 26 | exit; 27 | } elsif (lc $arg eq "-o") { 28 | $optimize = 1; 29 | } elsif (lc $arg =~ /-b(\d+)/) { 30 | $bottom = $1; 31 | } elsif (lc $arg =~ /-t(\d+)/) { 32 | $top = $1; 33 | } elsif (lc $arg =~ /-r(\d+)/) { 34 | $res = $1; 35 | } elsif (lc $arg eq "-s") { 36 | $makefile = 1; 37 | } elsif (lc $arg eq "-n") { 38 | $newline = ""; 39 | } else { 40 | die "Invalid option: $arg! Skipping\nExit\n"; 41 | } 42 | } 43 | 44 | while(defined($line = )) { 45 | chomp $line; 46 | next if $line !~ /^\d+\s+\d+/; 47 | ($c,$w) = $line =~ /^(\d+)\s+(\d+)/; 48 | $w2c{$w} += $c; 49 | } 50 | 51 | if ($makefile) { 52 | print STDOUT "Count\tWidth\n"; 53 | foreach $w (sort {$w2c{$b} <=> $w2c{$a} or $a <=> $b} keys %w2c) { 54 | print STDOUT "$w2c{$w}\t$w\n"; 55 | } 56 | } elsif (not $optimize) { 57 | foreach $w (sort {$a <=> $b} keys %w2c) { 58 | $hicount = $w2c{$w} and $hiwidth = $w if $w2c{$w} > $hicount; 59 | } 60 | print STDOUT "$hiwidth (x $w2c{$hiwidth})$newline"; 61 | } else { 62 | $index = &getindex($bottom,$top); 63 | $buffer = "[$index]"; 64 | foreach $size ($index - 10 .. $index + 10) { 65 | delete $w2c{$size}; 66 | } 67 | $index = &getindex($bottom,$top); 68 | $buffer .= " " . $index; 69 | foreach $size ($index - 10 .. $index + 10) { 70 | delete $w2c{$size}; 71 | } 72 | $index = &getindex($bottom,$top); 73 | $buffer .= " " . $index; 74 | print STDOUT "$buffer$newline"; 75 | } 76 | 77 | sub scandata ($$) { 78 | my ($index,$range) = @_; 79 | $result = 0; 80 | foreach $c ($index - $range .. $index + $range) { 81 | if ($c > 0 and $c < 1000) { 82 | $result += $w2c{$c}; 83 | } 84 | } 85 | return $result; 86 | } 87 | 88 | sub getrange ($) { 89 | my ($range) = @_; 90 | my ($number,$index) = (0,0); 91 | foreach $i (sort {$a <=> $b} keys %w2c) { 92 | $temp = &scandata($i,$range); 93 | if ($temp > $number) { 94 | $index = $i; 95 | $number = $temp; 96 | } 97 | } 98 | return $index; 99 | } 100 | 101 | sub getindex ($$) { 102 | my ($bottom,$top) = @_; 103 | my ($number,$index) = (0,0); 104 | foreach $size ($bottom * 2 .. $top * 2) { 105 | $count{&getrange(&rnd(0.35 * (72000 / (($size / 2) * $res))))} += 1; 106 | } 107 | foreach $i (sort {$a <=> $b} keys %count) { 108 | $index = $i and $number = $count{$i} if $count{$i} > $number; 109 | } 110 | undef %count; 111 | return $index; 112 | } 113 | 114 | sub rnd ($) { 115 | my ($arg) = @_; 116 | if ($arg =~ /\.[0-4]\d*/) { 117 | $arg =~ s/\.[0-4]\d*$//; 118 | } elsif ($arg =~ /\.[5-9]\d*/) { 119 | $arg =~ s/(\d+)\.[5-9]\d*$/$1 + 1/e; 120 | } 121 | return $arg; 122 | } 123 | 124 | sub fix { 125 | my ($string) = @_; 126 | $string =~ s/^ //gm; 127 | return $string; 128 | } 129 | 130 | sub ShowUsage { 131 | print STDOUT &fix(<] [-t] [-r]] [-n] < stemHist-generated-stemwidth-reports 138 | 139 | Calculates highest-frequency or optimal stem width values in one or more 140 | stemHist-generated stemwidth reports. 141 | 142 | ENDUSAGE 143 | } 144 | 145 | sub ShowHelp { 146 | print STDOUT &fix(< < \n"; 24 | exit; 25 | } elsif ($ARGV[0] =~ /^-[kK]/) { 26 | print STDERR "Note: Inserting 'hang' script tag\n"; 27 | $hang = 1; 28 | shift; 29 | } else { 30 | $file = $ARGV[0]; 31 | shift; 32 | } 33 | } 34 | 35 | print STDERR "Storing CMap resource mappings into lookup structure..."; 36 | while (defined($line = )) { 37 | if ($data or $line =~ /begincid(?:char|range)/) { 38 | $data = 1; 39 | } else { 40 | next; 41 | } 42 | if ($line !~ /^\s*<([\da-fA-F]{8})>\s+(?:<([\da-fA-F]{8})>\s+)?(\d+)\s*$/) { 43 | next; 44 | } else { 45 | $begin = $1; 46 | if (not defined $2) { 47 | $end = $begin; 48 | } else { 49 | $end = $2; 50 | } 51 | $cid = $3; 52 | } 53 | foreach $char (hex($begin) .. hex($end)) { 54 | if ($char >= hex("00004E00") and $char <= hex("00009FFF") or 55 | $char >= hex("00003400") and $char <= hex("00004DBF") or 56 | $char >= hex("0000F900") and $char <= hex("0000FAD9") or 57 | # Kana and hangul are generally excluded from the calculation, but 58 | # should be uncommented as appropriate for kana- or hangul-only 59 | # fonts: 60 | # $char >= hex("00003041") and $char <= hex("00003096") or 61 | # $char >= hex("000030A1") and $char <= hex("000030FA") or 62 | # $char >= hex("0000AC00") and $char <= hex("0000D7A3") or 63 | $char >= hex("00020000") and $char <= hex("0002FFFD")) { 64 | $code = sprintf("%08X",$char); 65 | $cid2code{$cid} = $code; 66 | $count++; 67 | $cid++; 68 | } 69 | } 70 | } 71 | print STDERR "Done.\n"; 72 | 73 | open(AFM,"tx -afm $file |") or die "Cannot open $file input file!\n"; 74 | 75 | print STDERR "Storing AFM records for "; 76 | while (defined($line = )) { 77 | chomp $line; 78 | if ($line =~ /^FontName/) { 79 | ($fontname) = $line =~ /^FontName\s+(.*)$/; 80 | print STDERR "\"$fontname\" CIDFont into lookup structure..."; 81 | } elsif ($line =~ /^StartCharMetrics/) { 82 | while ($line !~ /^EndCharMetrics/) { 83 | chomp($line = ); 84 | ($width,$cid,$bbox,$a,$b,$c,$d) = $line =~ m{ 85 | ^ 86 | \s* C \s+ -?\d+ \s+ ; \s+ 87 | W0X \s+ (\d+) \s+ ; \s+ 88 | N \s+ (\d+) \s+ ; \s+ 89 | B \s+ ((-?\d+) \s+ (-?\d+) \s+ (-?\d+) \s+ (-?\d+)) \s+ ; \s* 90 | $ 91 | }x; 92 | if (exists $cid2code{$cid}) { 93 | $num++; 94 | if ($bbox ne "0 0 0 0") { 95 | $llx += $a; 96 | $lly += $b; 97 | $urx += $c; 98 | $ury += $d; 99 | } 100 | } 101 | } 102 | } 103 | } 104 | print STDERR "Done.\n"; 105 | close(AFM); 106 | 107 | $left = $llx / $num; 108 | $right = 1000 - ($urx / $num); 109 | $bottom = 120 + ($lly / $num); 110 | $top = 880 - ($ury / $num); 111 | 112 | $result = ($left + $right + $bottom + $top) / 4; 113 | 114 | $left = $result; 115 | $right = 1000 - $result; 116 | $bottom = -120 + $result; 117 | $top = 880 - $result; 118 | 119 | if ($hang) { 120 | print STDOUT <= 110; $y -= 34.25) { # 34.25 was 29.25 ; 110 was 140; 658 was 608 50 | print STDOUT " newpath 62 $y M 478 0 rlineto .5 setlinewidth stroke"; 51 | } 52 | print STDOUT " /SourceCodePro-Semibold 25.25 selectfont"; 53 | 54 | $x = 78.8755; 55 | 56 | foreach $number (0 .. 15) { 57 | $new = sprintf("%01X",$number); 58 | print STDOUT " $x 663.03 M ($new) W"; 59 | $x += 29.25; 60 | } 61 | 62 | $y = 635.78; 63 | 64 | foreach $number (0 .. 15) { 65 | $new = sprintf("%01X",$number); 66 | print STDOUT " 52.25 $y M ($new) W"; 67 | $y -= 34.25; 68 | } 69 | print STDOUT " } bind def\n\n"; 70 | 71 | undef $/; 72 | open(CMAP,"<$cmap") or die "No dice! $cmap!\n"; 73 | $data = ; 74 | close(CMAP); 75 | %cmap = &GetData($data); # Read in CMap file's information 76 | %single_mappings = &StoreMappings($cmap{Mappings}) if exists $cmap{Mappings}; 77 | 78 | foreach $code (sort keys %single_mappings) { 79 | ($row) = $code =~ /^0x([0-9A-Fa-f]*)[0-9A-Fa-f][0-9A-Fa-f]$/; 80 | $row = hex $row; 81 | $rows{$row} = 1 if not exists $rows{$row}; 82 | } 83 | 84 | $ros = "$cmap{Registry}-$cmap{Ordering}-$cmap{Supplement}"; 85 | $ro = "$cmap{Registry}-$cmap{Ordering}"; 86 | 87 | if ($ro eq "Adobe-GB1") { 88 | foreach $cid (1 .. 95, 7712 .. 7715, 22353, 22354) { $widths{$cid} = "P" } 89 | foreach $cid (814 .. 939, 7716, 22355 .. 22357) { $widths{$cid} = "H" } 90 | foreach $cid (0 .. 7716) { $supp{$cid} = "0" } 91 | foreach $cid (7717 .. 9896) { $supp{$cid} = "1" } 92 | foreach $cid (9897 .. 22126) { $supp{$cid} = "2" } 93 | foreach $cid (22127 .. 22352) { $supp{$cid} = "3" } 94 | foreach $cid (22353 .. 29063) { $supp{$cid} = "4" } 95 | foreach $cid (29064 .. 30283) { $supp{$cid} = "5" } 96 | foreach $cid (30284 .. 30571) { $supp{$cid} = "6" } 97 | } elsif ($ro eq "Adobe-CNS1") { 98 | foreach $cid (1 .. 98, 17601) { $widths{$cid} = "P" } 99 | foreach $cid (13648 .. 13742, 17603) { $widths{$cid} = "H" } 100 | foreach $cid (0 .. 14098) { $supp{$cid} = "0" } 101 | foreach $cid (14099 .. 17407) { $supp{$cid} = "1" } 102 | foreach $cid (17408 .. 17600) { $supp{$cid} = "2" } 103 | foreach $cid (17601 .. 18845) { $supp{$cid} = "3" } 104 | foreach $cid (18846 .. 18964) { $supp{$cid} = "4" } 105 | foreach $cid (18965 .. 19087) { $supp{$cid} = "5" } 106 | foreach $cid (19088 .. 19155) { $supp{$cid} = "6" } 107 | foreach $cid (19156 .. 19178) { $supp{$cid} = "7" } 108 | } elsif ($ro eq "Adobe-CNS2") { 109 | foreach $cid (0 .. 55879) { $supp{$cid} = "0" } 110 | } elsif ($ro eq "Adobe-Japan1") { 111 | foreach $cid (1 .. 230, 9354 .. 9737, 15449 .. 15975, 20317 .. 20426) { $widths{$cid} = "P" } 112 | foreach $cid (231 .. 632, 8718, 8719, 12063 .. 12087) { $widths{$cid} = "H" } 113 | foreach $cid (9738 .. 9757) { $widths{$cid} = "Q" } 114 | foreach $cid (9758 .. 9778) { $widths{$cid} = "T" } 115 | foreach $cid (0 .. 8283) { $supp{$cid} = "0" } 116 | foreach $cid (8284 .. 8358) { $supp{$cid} = "1" } 117 | foreach $cid (8359 .. 8719) { $supp{$cid} = "2" } 118 | foreach $cid (8720 .. 9353) { $supp{$cid} = "3" } 119 | foreach $cid (9354 .. 15443) { $supp{$cid} = "4" } 120 | foreach $cid (15444 .. 20316) { $supp{$cid} = "5" } 121 | foreach $cid (20317 .. 23057) { $supp{$cid} = "6" } 122 | foreach $cid (23058 .. 23059) { $supp{$cid} = "7" } 123 | } elsif ($ro eq "Adobe-Japan2") { 124 | foreach $cid (0 .. 6067) { $supp{$cid} = "0" } 125 | } elsif ($ro eq "Adobe-Korea1") { 126 | foreach $cid (1 .. 100) { $widths{$cid} = "P" } 127 | foreach $cid (8094 .. 8190) { $widths{$cid} = "H" } 128 | foreach $cid (0 .. 9332) { $supp{$cid} = "0" } 129 | foreach $cid (9333 .. 18154) { $supp{$cid} = "1" } 130 | foreach $cid (18155 .. 18351) { $supp{$cid} = "2" } 131 | } elsif ($ro eq "Adobe-KR") { 132 | foreach $cid (0, 119, 128, 132, 135, 136, 138 .. 147, 152 .. 155, 158 .. 169, 11451 .. 11877, 11895, 11923 .. 11925, 11932 .. 11976, 11978 .. 12107, 12151 .. 12234, 14238 .. 22479, 22690 .. 22896) { $widths{$cid} = "F" } 133 | foreach $cid (109, 170 .. 3000, 3053 .. 3056, 3059 .. 11450, 12108 .. 12150, 12237 .. 13500) { $widths{$cid} = "M" } 134 | foreach $cid (13501 .. 14237) { $widths{$cid} = "Z" } 135 | foreach $cid (12235, 12236) { $widths{$cid} = "Q" } 136 | foreach $cid (3057, 3058) { $widths{$cid} = "W" } 137 | foreach $cid (1 .. 108, 110 .. 118, 120 .. 127, 129 .. 131, 133, 134, 137, 148 .. 151, 156, 157, 3001 .. 3052, 11878 .. 11894, 11896 .. 11922, 11926 .. 11931, 11977, 22480 .. 22689) { $widths{$cid} = "P" } 138 | foreach $cid (0 .. 3058) { $supp{$cid} = "0" } 139 | foreach $cid (3059 .. 4636) { $supp{$cid} = "1" } 140 | foreach $cid (4637 .. 11450) { $supp{$cid} = "2" } 141 | foreach $cid (11451 .. 11730) { $supp{$cid} = "3" } 142 | foreach $cid (11731 .. 11877) { $supp{$cid} = "4" } 143 | foreach $cid (11878 .. 12234) { $supp{$cid} = "5" } 144 | foreach $cid (12235 .. 14237) { $supp{$cid} = "6" } 145 | foreach $cid (14238 .. 18857) { $supp{$cid} = "7" } 146 | foreach $cid (18858 .. 22479) { $supp{$cid} = "8" } 147 | foreach $cid (22480 .. 22896) { $supp{$cid} = "9" } 148 | } 149 | 150 | print STDERR "CIDFont: $cidfont CMap: $cmap ROS: $ros\n"; 151 | 152 | foreach $row (sort {$a <=> $b} keys %rows) { 153 | print STDERR "$row -> "; 154 | $row = sprintf("%0${len}X",$row); 155 | if (length($row) == 6) { 156 | if ($row =~ /^00(10)([0-9A-Fa-f][0-9A-Fa-f])$/) { 157 | $newrow = "U+$1" . $2 . "xx"; 158 | } elsif ($row =~ /^000([1-9A-Fa-f])([0-9A-Fa-f][0-9A-Fa-f])$/) { 159 | $newrow = "U+$1" . $2 . "xx"; 160 | } else { 161 | $row =~ /^0000([0-9A-Fa-f][0-9A-Fa-f])$/; 162 | $newrow = "U+" . $1 . "xx"; 163 | } 164 | } else { 165 | $newrow = "U+" . $row . "xx"; 166 | } 167 | print STDERR "$newrow\n"; 168 | print STDOUT "T (Row $newrow: $cmap) S 698 M"; 169 | print STDOUT " (Row $newrow: $cmap) W\n($ros) S 75 M\n($ros) W\nF\n"; 170 | 171 | $count = 1; 172 | $x = 74; 173 | $y = 633.78; 174 | 175 | foreach $item (0 .. 255) { 176 | $cell = sprintf("%02X",$item); 177 | $newcode = "0x" . $row . $cell; 178 | if (exists $single_mappings{$newcode}) { 179 | print STDOUT "<$row$cell> S1 $x E $y M <$row$cell> W C"; 180 | $savex = $x; 181 | $savey = $y; 182 | if (exists $widths{$single_mappings{$newcode}}) { 183 | $x -= 1; 184 | $y += 19.5; 185 | print STDOUT " $x $y M ($widths{$single_mappings{$newcode}}) W"; 186 | } 187 | $x = $savex; 188 | $y = $savey; 189 | $x += 23.5; 190 | $y += 19.5; 191 | print STDOUT " $x $y M ($supp{$single_mappings{$newcode}}) W"; 192 | $x = $savex; 193 | $y = $savey; 194 | $y -= 8; 195 | print STDOUT " ($single_mappings{$newcode}) S1 $x E $y"; 196 | print STDOUT " M ($single_mappings{$newcode}) W F\n"; 197 | $x = $savex; 198 | $y = $savey; 199 | } 200 | $x += 29.25; 201 | if ($count >= 16) { 202 | $y -= 34.25; # Was 29.25 203 | $x = 74; 204 | $count = 1; 205 | } else { 206 | $count++; 207 | } 208 | } 209 | print STDOUT "BX SP\n"; 210 | } 211 | 212 | sub GetData ($) { # For extracting CMap information 213 | my ($cmapfile) = @_; 214 | my ($usecmap,$r,$o,$s,$name,$version,$uidoffset,$xuid,$wmode) = ("","","","","","","","",""); 215 | my ($codespacerange,$notdefrange,$mappings) = ("","",""); 216 | undef %data; 217 | 218 | ($usecmap) = $cmapfile =~ m{/([0-9a-zA-Z-]+)\s+usecmap}; 219 | 220 | ($r,$o,$s) = $cmapfile =~ m{ 221 | \s* /CIDSystemInfo \s+ \d+ \s+ dict \s+ dup \s+ begin 222 | \s* /Registry \s+ \( (.+) \) \s+ def 223 | \s* /Ordering \s+ \( (.+) \) \s+ def 224 | \s* /Supplement \s+ (\d+) \s+ def 225 | \s* end \s+ def 226 | }msx; 227 | 228 | ($name) = $cmapfile =~ m{/CMapName\s+/([0-9a-zA-Z-]+)\s+def}; 229 | ($version) = $cmapfile =~ m{/CMapVersion\s+(\d+(?:\.\d*))\s+def}; 230 | ($uidoffset) = $cmapfile =~ m{(/UIDOffset\s+\d+)\s+def}; 231 | ($xuid) = $cmapfile =~ m{/XUID\s+\[([0-9 ]+)\]\s+def}; 232 | ($wmode) = $cmapfile =~ m{/WMode\s+([01])\s+def}; 233 | ($codespacerange) = $cmapfile =~ m{ 234 | ( 235 | \d+ 236 | \s+ 237 | begincodespacerange 238 | .+ 239 | endcodespacerange 240 | \s 241 | ) 242 | }msx; 243 | ($notdefrange) = $cmapfile =~ m{ 244 | ( 245 | \s 246 | \d+ 247 | \s+ 248 | beginnotdefrange 249 | .+ 250 | endnotdefrange 251 | \s 252 | ) 253 | }msx; 254 | ($mappings) = $cmapfile =~ m{ 255 | ( 256 | \d+ 257 | \s+ 258 | begin(?:bf|cid)(?:char|range) 259 | .+ 260 | end(?:bf|cid)(?:char|range) 261 | ) 262 | \s+ 263 | endcmap 264 | }msx; 265 | 266 | $data{UseCMap} = $usecmap if $usecmap; 267 | $data{Registry} = $r if $r; 268 | $data{Ordering} = $o if $o; 269 | $data{Supplement} = $s if $s or $s eq "0"; 270 | $data{Name} = $name if $name; 271 | $data{Version} = $version if $version; 272 | $data{UIDOffset} = "$uidoffset def\n" if $uidoffset; 273 | $data{XUID} = $xuid if $xuid; 274 | $data{WMode} = $wmode if $wmode or $wmode eq "0"; 275 | $data{CodeSpace} = $codespacerange if $codespacerange; 276 | $data{NotDef} = $notdefrange if $notdefrange; 277 | $data{Mappings} = $mappings if $mappings; 278 | 279 | return %data; 280 | } 281 | 282 | sub StoreMappings ($) { 283 | my ($mappings) = @_; 284 | my $processed = 0; 285 | 286 | ($bforcid) = $mappings =~ /begin(bf|cid)(?:char|range)/; 287 | @lines = split(/[\r\n]+/,$mappings); 288 | 289 | print STDERR "Reading CMap file into a lookup structure..."; 290 | foreach $line (@lines) { 291 | $line = uc $line; 292 | if ($line =~ /^\s*<([\dA-F]+)>\s+(\d+)\s*$/) { # char 293 | $processed++; 294 | $hex = sprintf("%0${len1}X",hex($1)); 295 | if (not defined $mapping{"0x" . $hex}) { # MODIFIED 296 | $mapping{"0x" . $hex} = $2; #MODIFIED 297 | $expanded++; 298 | } else { 299 | printf STDERR "Duplicate mapping at %0${len1}X!\n",hex($1); 300 | } 301 | } elsif ($line =~ /^\s*<([\dA-F]+)>\s+<([\dA-F]+)>\s+(\d+)\s*$/) { # range 302 | $processed++; 303 | $cid = $3; 304 | foreach $dec (hex($1) .. hex($2)) { 305 | $hex = sprintf("%0${len1}X",$dec); 306 | if (not defined $mapping{"0x" . $hex}) { # MODIFIED "0x" . 307 | $mapping{"0x" . $hex} = $cid; # MODIFIED 308 | } else { 309 | printf STDERR "Duplicate mapping at %0${len1}X!\n",$dec; 310 | } 311 | $expanded++; 312 | $cid++; 313 | } 314 | } 315 | } 316 | print STDERR "Done.\n"; 317 | print STDERR "Processed $processed CMap lines into $expanded mappings.\n"; 318 | return %mapping; 319 | } 320 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Perl Scripts 2 | 3 | This project includes an assortment of command-line Perl scripts that are useful for font development, and run in terminal apps, such as *Terminal* on macOS, and *Command Prompt* on Windows. 4 | 5 | ## Descriptions 6 | 7 | ### `cmap-tool.pl` 8 | 9 | Run `cmap-tool.pl < STDIN > STDOUT` to compile (default) or decompile a CMap resource. The input file must already follow CMap resource syntax, and output is to STDOUT. Compiling means to efficiently use the `begincidchar`/`endcidchar` and `begincidrange`/`endcidrange` operators whereby the latter is used to efficiently represent contiguous code points whose CIDs are also contiguous, and to include in each declared `begincidchar`/`endcidchar` and `begincidrange`/`endcidrange` section no more than 100 records. The mappings are validated against the `begincodespacerange`/`endcodespacerange` section, and are also sorted according to it. When compiling a UTF-32 CMap resource, which is determined by the string "UTF32" being included in the CMap resource's name, corresponding UTF-8 and UTF-16 CMap resources are automatically generated. 10 | 11 | `-e`: This option decompiles the `begincidchar`/`endcidchar` and `begincidrange`/`endcidrange` sections into a single `begincidchar`/`endcidchar` section. If a UTF-32 CMap resource is being decompiled, corresponding UTF-8 and UTF-16 CMap resources are not generated. 12 | 13 | --- 14 | 15 | ### `fdarray-check.pl` 16 | 17 | Run `fdarray-check.pl > STDOUT` to report to STDOUT the FDArray structure of a CID-keyed font—instantiated as a CIDFont resource, CFF resource, or OpenType/CFF font—that shows the ROS (/Registry, /Ordering, and /Supplement) and the name of each FDArray element, along with its index in parentheses, the CIDs and CID ranges that are assigned to it, and the total number of CIDs in parentheses. The CIDs are prefixed with a slash to explicitly indicate CIDs, as opposed to GIDs, which is useful when using the `-g` or `-gx` command-line options for many AFDKO tools, especially when GIDs do not equal CIDs in a particular font. 18 | 19 | The following output example is from [*Ten Mincho Regular*](https://typekit.com/fonts/ten-mincho): 20 | 21 | Detected ROS: Adobe-Identity-0 22 | TenMincho-Regular-Alphabetic (0): /7434-/7444,/7452-/7477,/7484-/7509 (63) 23 | TenMincho-Regular-Dingbats (1): /0,/103,/112-/113,/118,/151,/183,/388-/389,/549,/554-/555,/562-/563,/565-/569,/572,/610-/612,/625-/629,/632,/636-/637,/640-/642,/645-/661,/663-/672,/675-/686,/688-/725,/813-/816,/911,/7391-/7433,/7445-/7451,/7478-/7483,/7510-/7520,/7921-/7944,/8197-/8206,/8236-/8242,/8270-/8279 (234) 24 | TenMincho-Regular-Emoji (2): /8193-/8196,/8280-/8283 (8) 25 | TenMincho-Regular-HWidth (3): /7911-/7920 (10) 26 | TenMincho-Regular-Italic (4): /8284-/9116 (833) 27 | TenMincho-Regular-Kana (5): /726-/812,/817-/910,/912-/915,/8207-/8235 (214) 28 | TenMincho-Regular-Kanji (6): /916-/7325,/7328-/7384,/7521-/7522 (6469) 29 | TenMincho-Regular-Proportional (7): /1-/102,/104-/111,/114-/117,/119-/150,/152-/182,/184-/387,/390-/548,/550-/553,/556-/561,/564,/570-/571,/573-/609,/613-/624,/630-/631,/633-/635,/638-/639,/643-/644,/662,/673-/674,/687,/7326-/7327,/7385-/7390,/7523-/7724,/7945-/7983,/7992-/8192 (1065) 30 | TenMincho-Regular-ProportionalJapanese (8): /7984-/7991 (8) 31 | TenMincho-Regular-Ruby (9): /7725-/7910,/8243-/8269 (213) 32 | 33 | `-g`: This option suppresses the slash prefix for CIDs and CID ranges. 34 | 35 | Tool Dependencies: `tx` 36 | 37 | --- 38 | 39 | ### `fix-fontbbox.pl` 40 | 41 | Run `fix-fontbbox.pl > STDOUT` to check and correct the /FontBBox array of a CIDFont resource. The original and corrected /FontBBox array values are reported to STDERR. 42 | 43 | Tool Dependencies: `tx` 44 | 45 | --- 46 | 47 | ### `glyph-list.pl` 48 | 49 | Run `glyph-list.pl > STDOUT` to list the glyphs in the specified font, which can be a CIDFont resource, a name-keyed Type 1 font (aka PFA), UFO, or an 'sfnt' (TrueType or OpenType) font. Glyphs are listed as CIDs or glyph names, depending on whether the font is CID- or name-keyed. CIDs are prefixed with a slash. 50 | 51 | `-g`: This option lists GIDs instead of CIDs or glyph names. 52 | `-r`: This option outputs the list of CIDs as ranges, or as a single GID range if the `-g` command-line option is also specified. 53 | `-s`: This option outputs a single line that uses a comma as a separator so that it can be repurposed, such as to be used as the argument of the `-g` or `-gx` command-line options that are supported by many AFDKO tools. 54 | 55 | Tool Dependencies: `tx` 56 | 57 | --- 58 | 59 | ### `hintcidfont.pl` 60 | 61 | Run `hintcidfont.pl < STDIN > STDOUT` to apply hinting parameters to a CIDFont resource. A hinting parameter file (a sample hinting parameter file is provided at the end of the script, after the `__END__` declaration) serves as its only argument, and uses it to apply hinting parameters, such as alignment zones and stem values, to the header of a CIDFont resource that is specified as STDIN. A new CIDFont resource is written to STDOUT, which subsequently needs to be processed by the AFDKO `autohint` tool to apply the hinting parameters to the glyphs. 62 | 63 | Special Note: The /FontName of each FDArray element as specified in the CIDFont resource header must be in a form that includes the /CIDFontName plus a unique identifier, such as `Dingbats`. For *Source Han Sans ExtraLight*, the /FontName would be `SourceHanSans-ExtraLight-Dingbats`. The hinting parameter file specifies only the unique identifier, such as `Dingbats` in the example. 64 | 65 | --- 66 | 67 | ### `mkicf.pl` 68 | 69 | Run `mkicf.pl < STDIN > STDOUT` to output to STDOUT a ready-to-use '[BASE](https://docs.microsoft.com/en-us/typography/opentype/spec/base)' table override declaration that can be included in a "features" file that is used as input to the AFDKO `makeotf` tool as an argument of its `-ff` command-line option. A CIDFont resource serves as the only argument, a UTF-32 CMap resource is specified as STDIN, and these are used to calculate appropriate ICF (*Ideographic Character Face*) values. The output may look like the following: 70 | 71 | table BASE { 72 | HorizAxis.BaseTagList icfb icft ideo romn; 73 | HorizAxis.BaseScriptList DFLT ideo -78 838 -120 0, 74 | hani ideo -78 838 -120 0, 75 | kana ideo -78 838 -120 0, 76 | latn romn -78 838 -120 0, 77 | cyrl romn -78 838 -120 0, 78 | grek romn -78 838 -120 0; 79 | 80 | VertAxis.BaseTagList icfb icft ideo romn; 81 | VertAxis.BaseScriptList DFLT ideo 42 958 0 120, 82 | hani ideo 42 958 0 120, 83 | kana ideo 42 958 0 120, 84 | latn romn 42 958 0 120, 85 | cyrl romn 42 958 0 120, 86 | grek romn 42 958 0 120; 87 | } BASE; 88 | 89 | `-k`: This option adds the 'hang' (hangul) script tag to the 'BASE' table override declaration. 90 | 91 | Tool Dependencies: `tx` 92 | 93 | --- 94 | 95 | ### `mklocl.pl` 96 | 97 | Run `mklocl.pl -i -o > STDOUT` to synthesizes a lookup for the '[locl](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ko#a-namelocl-idloclatag-39locl39)' (_Localized Forms_) GSUB feature by specifying two region or language identifiers, whereby the input one is considered the default region or language in terms of which glyphs are encoded by default, and the output one represents a non-default region or language. Only those code points whose CIDs are different for the two specified regions or languages are included in the lookup declaration that is output to STDOUT. The input and output files, whose lines individually map eight-digit UTF-32 character codes to CIDs, and whose names must follow the pattern `utf32-.map`, serve as the arguments of the `-i` and `-o` command-line options, respectively, and the region or language identifiers in their names are used for synthesizing the names of the lookup declarations. The input and output files must also be present in the current working directory. 98 | 99 | This script must be run one time less than the number of supported regions or languages of the font. If a font supports the CN, TW, HK, JP, and KR regions, and if the default region is JP, then this script would be run four times as follows: 100 | 101 | % mklocl.pl -i utf32-jp.map -o utf32-cn.map > STDOUT 102 | % mklocl.pl -i utf32-jp.map -o utf32-tw.map >> STDOUT 103 | % mklocl.pl -i utf32-jp.map -o utf32-hk.map >> STDOUT 104 | % mklocl.pl -i utf32-jp.map -o utf32-kr.map >> STDOUT 105 | 106 | This script was used for [_Source Han Sans_](https://github.com/adobe-fonts/source-han-sans/) and [_Source Han Serif_](https://github.com/adobe-fonts/source-han-serif/) development, and is therefore generally useful for Pan-CJK font development. 107 | 108 | `-i`: This option specifies the file name that includes the UTF-32 to CID mappings of the input (default) region or language whose name must follow the pattern `utf32-.map`. 109 | `-o`: This option specifies the file name that includes the UTF-32 to CID mappings of the output (non-default) region or language whose name must also follow the pattern `utf32-.map`. 110 | 111 | --- 112 | 113 | ### `mkrange.pl` 114 | 115 | Run `mkrange.pl < STDIN > STDOUT` to output a list of integer (default) or hexadecimal values as ranges of contiguous values using a hyphen as a separator. No sorting is performed, and integer values can be prefixed with a slash (the use of a slash prefix explicitly specifies CID values, as opposed to GID values, which is useful for CID-keyed font development). 116 | 117 | `-h`: This option must be specified if the list is of hexadecimal values. 118 | `-s`: This option outputs a single line that uses a comma as a separator so that it can be repurposed, such as to be used as the argument of the `-g` or `-gx` command-line options that are supported by many AFDKO tools. 119 | 120 | --- 121 | 122 | ### `mkvmtx.pl` 123 | 124 | Run `mkvmtx.pl < STDIN > STDOUT` to output to STDOUT a ready-to-use '[vmtx](https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx)' table override declaration that can be included in a "features" file that is used as input to the AFDKO `makeotf` tool as an argument of its `-ff` command-line option. A CIDFont resource serves as the only argument, and STDIN is a list of CIDs and CID ranges that correspond to full-width glyphs that rest on the Western baseline, such as Latin, Greek, Cyrillic, currency symbols, and other characters. The specified CIDs are mechanically centered along the Y-axis by using the top and bottom of the em-box as reference points, along with the top and bottom of their bounding boxes. If a CID does not require adjustment, meaning that its glyph is already centered along the Y-axis, it is omitted from the output. Below is example output that uses CIDs 710 through 720: 125 | 126 | table vmtx { 127 | VertOriginY \710 889; 128 | VertOriginY \711 860; 129 | VertOriginY \712 847; 130 | VertOriginY \713 860; 131 | VertOriginY \714 860; 132 | VertOriginY \715 860; 133 | VertOriginY \716 860; 134 | VertOriginY \717 844; 135 | VertOriginY \719 871; 136 | VertOriginY \720 818; 137 | } vmtx; 138 | 139 | Please see the [Resources](Resources) directory for the following pre-made lists of CIDs and CID ranges for Adobe's public ROSes: *vmtx.AC17* (Adobe-CNS1-7), *vmtx.AG15* (Adobe-GB1-5), *vmtx.AJ16* (Adobe-Japan1-6), *vmtx.AK12* (Adobe-Korea1-2), and *vmtx.AKR9* (Adobe-KR-9). 140 | 141 | Tool Dependencies: `tx` 142 | 143 | --- 144 | 145 | ### `proof.pl` 146 | 147 | Run `proof.pl