summaryrefslogtreecommitdiff
path: root/fonts/utilities/mf2pt3/mf2pt3.nw
diff options
context:
space:
mode:
Diffstat (limited to 'fonts/utilities/mf2pt3/mf2pt3.nw')
-rw-r--r--fonts/utilities/mf2pt3/mf2pt3.nw530
1 files changed, 530 insertions, 0 deletions
diff --git a/fonts/utilities/mf2pt3/mf2pt3.nw b/fonts/utilities/mf2pt3/mf2pt3.nw
new file mode 100644
index 0000000000..a7393932c7
--- /dev/null
+++ b/fonts/utilities/mf2pt3/mf2pt3.nw
@@ -0,0 +1,530 @@
+<b>mf2pt3</b> (c) Copyright 1998 Apostolos Syropoulos
+[[apostolo@obelix.ee.duth.gr]] <p>
+This is program [[mf2pt3]] a Perl script that generates a PostScript
+Type 3 font that corresponds to a METAFONT font description. In order
+to achieve its goal the program utilizes another program: mfplain
+(METAPOST with the mfplain base preloaded). This program generates EPSF
+files for each character. This document assumes that the reader is
+familiar with the Type 3 font terminology and its structure. For
+more information one should consult the ``PostScript User Manual'',
+or any good book on PostScript like ``Postscript by Example'',
+by Henry McGilton and Mary Campione, published by Addison-Wesley Pub Co.
+
+@ We now describe the way the program operates. First of all, we
+generate for each character of a METAFONT font an EPSF file. Next
+we collect the [[BoundingBox]] information for each character, as this
+piece of information is vital to the construction of the Type 3 font.
+Now we can proceed with the construction of the font. Finally, we
+delete some unnecessary files and we output the line the user must
+add to his/her [[psfonts.map]] file in order to use the Type 3 font
+when he/she creates a PostScript file from a DVI file.
+
+<<*>>=
+#!/usr/bin/perl
+#
+#(c) Copyright 1998 Apostolos Syropoulos
+# apostolo@obelix.ee.duth.gr
+#
+<<Initialization of constants>>
+<<Command line argument handling>>
+<<Generation of EPSF files>>
+<<Construction of Type 3 font>>
+<<Delete unnecessary files>>
+print "\n$MFfile $MFfile <$MFfile.pt3\n";
+
+@ Since we don't know on what system the program will be used, we
+must make sure it calls the GhostScript and METAPOST programs in the proper
+way. Moreover, we supply to each command the proper command line switches.
+The magnification is set to 100 as the usual design size is 10 pt.
+The [[BoundingBox]] information are kept in a compact format in an array.
+
+<<Initialization of constants>>=
+ $mfplain="mfplain \'\\mode=localfont; \\batchmode; ";
+ <<BoundingBox initialization>>
+ <<Encoding array initialization>>
+
+@ Since Perl does not provide record structures, we use the [[pack]]
+function to create a structure which will contain the [[BoundingBox]]
+information. Each [[BoundingBox]] corresponds to four numbers: [[llx]],
+[[lly]], [[urx]], and [[ury]]. If any of the 256 character slots is
+undefined each of these four numbers is set to zero. For efficiency reasons
+each [[BoundingBox]] structure contains one more piece of information--- an
+ASCII character, which indicates whether the corresponding character is
+defined ("d") or undefined ("u"). All the [[BoundingBox]] information are
+kept in an array which is assumed to contain only undefined characters.
+
+<<BoundingBox initialization>>=
+$notdef=pack("ai4","u",0,0,0,0);
+for($i=0; $i<=255; $i++){ $BoundingBox[$i]=$notdef }
+
+@ The encoding vector is a vital part of a PostScript font. The internal
+name of each character is completely irrelevant to the final output. So,
+someone can choose any name it pleases him.
+
+<<Encoding array initialization>>=
+@Encoding = ("/_a0", "/_a1", "/_a2", "/_a3", "/_a4",
+ "/_a5", "/_a6", "/_a7", "/_a8",
+ "/_a9", "/_a10", "/_a11", "/_a12",
+ "/_a13", "/_a14", "/_a15", "/_a16",
+ "/_a17", "/_a18", "/_a19", "/_a20",
+ "/_a21", "/_a22", "/_a23", "/_a24",
+ "/_a25", "/_a26", "/_a27", "/_a28",
+ "/_a29", "/_a30", "/_a31", "/_a32",
+ "/_a33", "/_a34", "/_a35", "/_a36",
+ "/_a37", "/_a38", "/_a39", "/_a40",
+ "/_a41", "/_a42", "/_a43", "/_a44",
+ "/_a45", "/_a46", "/_a47", "/_a48",
+ "/_a49", "/_a50", "/_a51", "/_a52",
+ "/_a53", "/_a54", "/_a55", "/_a56",
+ "/_a57", "/_a58", "/_a59", "/_a60",
+ "/_a61", "/_a62", "/_a63", "/_a64",
+ "/_a65", "/_a66", "/_a67", "/_a68",
+ "/_a69", "/_a70", "/_a71", "/_a72",
+ "/_a73", "/_a74", "/_a75", "/_a76",
+ "/_a77", "/_a78", "/_a79", "/_a80",
+ "/_a81", "/_a82", "/_a83", "/_a84",
+ "/_a85", "/_a86", "/_a87", "/_a88",
+ "/_a89", "/_a90", "/_a91", "/_a92",
+ "/_a93", "/_a94", "/_a95", "/_a96",
+ "/_a97", "/_a98", "/_a99", "/_a100",
+ "/_a101", "/_a102", "/_a103", "/_a104",
+ "/_a105", "/_a106", "/_a107", "/_a108",
+ "/_a109", "/_a110", "/_a111", "/_a112",
+ "/_a113", "/_a114", "/_a115", "/_a116",
+ "/_a117", "/_a118", "/_a119", "/_a120",
+ "/_a121", "/_a122", "/_a123", "/_a124",
+ "/_a125", "/_a126", "/_a127", "/_a128",
+ "/_a129", "/_a130", "/_a131", "/_a132",
+ "/_a133", "/_a134", "/_a135", "/_a136",
+ "/_a137", "/_a138", "/_a139", "/_a140",
+ "/_a141", "/_a142", "/_a143", "/_a144",
+ "/_a145", "/_a146", "/_a147", "/_a148",
+ "/_a149", "/_a150", "/_a151", "/_a152",
+ "/_a153", "/_a154", "/_a155", "/_a156",
+ "/_a157", "/_a158", "/_a159", "/_a160",
+ "/_a161", "/_a162", "/_a163", "/_a164",
+ "/_a165", "/_a166", "/_a167", "/_a168",
+ "/_a169", "/_a170", "/_a171", "/_a172",
+ "/_a173", "/_a174", "/_a175", "/_a176",
+ "/_a177", "/_a178", "/_a179", "/_a180",
+ "/_a181", "/_a182", "/_a183", "/_a184",
+ "/_a185", "/_a186", "/_a187", "/_a188",
+ "/_a189", "/_a190", "/_a191", "/_a192",
+ "/_a193", "/_a194", "/_a195", "/_a196",
+ "/_a197", "/_a198", "/_a199", "/_a200",
+ "/_a201", "/_a202", "/_a203", "/_a204",
+ "/_a205", "/_a206", "/_a207", "/_a208",
+ "/_a209", "/_a210", "/_a211", "/_a212",
+ "/_a213", "/_a214", "/_a215", "/_a216",
+ "/_a217", "/_a218", "/_a219", "/_a220",
+ "/_a221", "/_a222", "/_a223", "/_a224",
+ "/_a225", "/_a226", "/_a227", "/_a228",
+ "/_a229", "/_a230", "/_a231", "/_a232",
+ "/_a233", "/_a234", "/_a235", "/_a236",
+ "/_a237", "/_a238", "/_a239", "/_a240",
+ "/_a241", "/_a242", "/_a243", "/_a244",
+ "/_a245", "/_a246", "/_a247", "/_a248",
+ "/_a249", "/_a250", "/_a251", "/_a252",
+ "/_a253", "/_a254", "/_a255");
+
+@ The program accepts at most five command line arguments:
+<ul>
+<li> [[-d size]] --- explicitly specify the [[$design_size]].</li>
+<li> [[-nodel]] --- suppress deleting of intermediate files,
+ such as [[foo.tfm]] or [[foo.ddd]].</li>
+<li> [[-eofill]] --- ignore <b>fill</b> commands that are not
+ immediately after <b>gsave</b>. If this happens
+ put <b>eofill</b> in the end of the character.
+<li> The UniqueID, i.e., a unique font identity number, if not specified the
+ program will automatically generate one</li>
+<li> The name of the METAFONT file with or without extension.</li>
+</ul>
+In case it is invoked without any command line arguments,
+it prints usage information. In order to properly use the program,
+one has to provide only the font name.
+
+@ Command line processing is being done in a relatively standard way.
+A while loop goes through each command line argument, checks its form
+and sets special global variables. In the case of the UniqueID argument
+we make sure it lies within the valid range, i.e., it is a number
+greater or equal than 4,000,000 and less than 5,000,000.
+
+@ Once we have finished with the scanning of the command line arguments
+we must further process certain pieces of information.
+
+<<Command line argument handling>>=
+$argc = @ARGV;
+$design_size = -1;
+$nodel = 0;
+$eofill = 0;
+$noID = 1;
+SWITCHES: while($_ = $ARGV[0], /^-/)
+{
+ shift;
+ if(/^-d(\d+)/)
+ {
+ $design_size = $1;
+ }
+ elsif(/^-nodel$/)
+ {
+ $nodel = 1;
+ }
+ elsif(/^-eofill$/)
+ {
+ $eofill = 1;
+ }
+ elsif(/^-I(\d+)$/)
+ {
+ die "UniqueID must lie in the range 4,000,000...4,999,999\n"
+ if ($1 > 4999999 || $1 < 4000000);
+ $UniqueID = $1;
+ $noID = 0;
+ }
+ elsif (!@ARGV)
+ {
+ last SWITCHES;
+ }
+}
+if (!@ARGV)
+{
+ print <<Usage;
+This ``mf2pt3'' version 1.1
+Usage: mf2pt3 [-dsize] [-nodel] [-eofill] [-IUniqueID] <METAFONT file name>
+Usage
+exit(0);
+}
+else
+{
+ $MFfile = $ARGV[0];
+}
+<<Further command line argument processing>>
+
+@ If the user has specified a Unique Font Identity number, the program
+must generate one. Moreover, if the user hasn't explicitly specified a
+design size, the program must extract it from the font name. Finally, we
+have to remove the file name extension in order to get the name of
+the new PostScript font.
+
+<<Further command line argument processing>>=
+if ($noID)
+{
+ <<Generate UniqueID>>
+}
+<<Get design size>>
+<<Remove file extension>>
+
+@ In case the user hasn't specified a UniqueID we must generate one
+For this purpose we use function [[rand]] and the random number generator
+seed ([[srand]]), in order to ensure some sort of... randomness.
+Since [[rand]] produces a number in
+the range 0...1, we multiply the output of [[rand]] by 999999 so that
+we have a number number in the range 0...999999, and we add to this
+the number 4000000 so that the final random number is in the expected
+range.
+
+<<Generate UniqueID>>=
+ srand();
+ $UniqueID = int(999999*rand())+4000000;
+
+@ As it is know a METAFONT font name consists of two parts: a symbolic
+acronym, specifying its characteristics, and a number specifying its
+design size. The number can be either a two or a four digit number (compare
+cmr17 with ecsx1095.) In both cases we extract the number from the
+font name and then in the first case we divide it by 10 and in the second
+case we divide it by 1000 to get the magnification factor. Finally, we
+set the magnification. The number 100 is chosen because font data
+must be integers greater than 100. Of course, nn case the user has already
+given the design size, there is no reason to extract if from the font name.
+But, still we must process it in oder to ensure the generation of valid
+output.
+
+<<Get design size>>=
+
+if ($design_size == -1)
+{
+ if ($MFfile =~ /\D+(\d+)$/)
+ {
+ $design_size=$1;
+ }
+ else
+ {
+ die "$MFfile must be a PostScript font name: there is no design size.\n";
+ }
+}
+if($design_size >100)
+{
+ $mag_factor=$design_size/1000;
+}
+else
+{
+ $mag_factor=$design_size/10;
+}
+$mag = 100 /$mag_factor;
+
+@ If the user supplies the METAFONT file name with an extension
+we simple chop it off. This is done pretty simple by employing Perl's
+fantastic regular-expression mechanism.
+
+<<Remove file extension>>=
+ $MFfile = $1 if $MFfile =~ /(\w+)\.\w*/;
+
+@ We proceed now to the generation of the EPSF files. This task
+is performed by METAPOST. Initially, we create the EPSF files by executing
+[[mfplain]]. If for some reason there is no TFM file, the program
+stops and prints an error message. (It is most likely that the user has
+typed the name of non-existing METAFONT font.) The [[$mfplain]] command
+is augmented by the magnification factor and the input part.
+
+<<Generation of EPSF files>>=
+ $mfplain .= "mag=$mag; input $MFfile \'";
+ system($mfplain);
+ if (!(-e "$MFfile.tfm"))
+ {
+ $nodel || unlink "mpout.log";
+ die "$MFfile: no such font in system\n";
+ }
+
+@ Since, the various EPSF files have been generated successfully, we
+can now start collecting the [[BoundingBox]] information. First, we
+get the names of all EPSF files. Next, we must open each EPSF file,
+and find the line that contains the [[BoundingBox]] information.
+This is easy, since in an EPSF file the line that contains this
+piece of information look like the following one:
+[[%%BoundingBox: 0 -1 6 6]]. While doing this we must get the
+[[FontBBox]] information. We use four variables for this purpose.
+The next step is produce the first part of the font, i.e., the
+metrics section and the encoding information.
+
+<<Construction of Type 3 font>>=
+ <<Get the file names of the EPSF files>>
+ $Min_llx = $Min_lly = $Max_urx = $Max_ury = 0;
+ <<get bounding boxes>>
+<<Generate Type 3 Font>>
+
+
+@ It could be easy to get the file names by a simple pipe, but
+since this program may be used in OS other that Unix, we prefer
+to do it in a more portable way--- we simply open the directory
+and store all the file names that fulfill with a name that is
+identical to [[$MFfile]].
+
+<<Get the file names of the EPSF files>>=
+ opendir(Dir, ".");
+ $pattern = "$MFfile" . "\\.\\d+";
+ @EPSFs = grep(/$pattern/, readdir(Dir));
+ closedir Dir;
+
+@ In order to get the [[BoundingBox]] information we open each
+EPSF file and we get the line that contains these information. For
+this we simply employ the pattern matching capabilities of Perl. Then
+we store these information in a compact way to the appropriate index
+in the [[BoundingBox]] array. (Readers not familiar with regular
+expressions should consult the Perl manual.) As a side effect we calculate
+the total number of characters that the font will provide in variable
+[[$total_chars]] (plus one as there is always the [[/.notdef]] character).
+
+<<get bounding boxes>>=
+
+ $total_chars = @EPSFs+1;
+ foreach $file (@EPSFs)
+ {
+ open(EPSF_FILE,"$file")||die "Can't open file $file\n";
+ while (<EPSF_FILE>)
+ {
+ $BBox = pack("ai4","d",$1,$2,$3,$4)
+ if /%%BoundingBox: (-?\d+) (-?\d+) (-?\d+) (-?\d+)/;
+ }
+ close EPSF_FILE;
+ $_=$file;
+ /$MFfile\.(\d+)/;
+ $BoundingBox[$1] = $BBox;
+ ($_, $llx, $lly, $urx, $ury) = unpack("ai4", $BBox);
+ $Min_llx = $llx if $llx < $Min_llx;
+ $Min_lly = $lly if $lly < $Min_lly;
+ $Max_urx = $urx if $urx > $Max_urx;
+ $Max_ury = $ury if $ury > $Max_ury;
+ }
+
+@ We now have all the information we need in order to generate the complete
+Type 3 font. We first, create the font file and then we print
+to it some information which are pretty standard, such as the [[/FontType]],
+etc. Next, we let PostScript know which characters will the font provide,
+and then we generate the [[BoundingBox]] dictionary, the [[Metrics]]
+dictionary, and the [[CharProcs]] dictionary. Finally, we generate the
+[[BuildGlyph]] procedure and we define the font.
+
+
+<<Generate Type 3 Font>>=
+ open(TYPE3, ">$MFfile.pt3")||die "Can't create file $MFfile.pt3\n";
+ $date = localtime;
+ print TYPE3 <<DATA;
+%!PS-Adobe-2.0
+%%Creator: mf2pt3 1.1 Copyright 1998 Apostolos Syropoulos
+%%CreationDate: $date
+%%EndComments
+11 dict % 11 entries
+begin
+ /FontType 3 def
+ /UniqueID $UniqueID def
+ /FontName /$MFfile def
+ /FontBBox [ $Min_llx $Min_lly $Max_urx $Max_ury] def
+ /FontMatrix [ 0.001 0 0 0.001 0 0 ] def
+ /Encoding 256 array def
+ 0 1 255 { Encoding exch /.notdef put } for
+DATA
+ <<make known all the characters of the font>>
+ <<generate bounding box dictionary>>
+ <<generate metrics dictionary>>
+ <<generate CharProcs dictionary>>
+<<generate BuildGlyph procedure>>
+
+@ After initializing the Encoding vector, we must make all those
+assignments so that PostScript will know which characters are in this font.
+This is trivial--- we simply scan the [[BoundingBox]] array and for
+each defined character we print a line of the form [[Encoding N Name]],
+where [[N]] is the number of the character and [[Name]] the [[N]]th
+entry in the Encoding array.
+
+<<make known all the characters of the font>>=
+ for($i=0; $i<=256; $i++)
+ {
+ $_ = unpack("ai4", $BoundingBox[$i]);
+ print TYPE3 "Encoding $i $Encoding[$i] put\n" if $_ eq "d";
+ }
+
+@ In general the bounding boxes dictionary consists of some of entries
+like the following one: [[/A [ 0 -100 600 700 ] def]]. Since, the numbers
+are stored in the [[BoundingBox]] array our task is simple. However we must
+print some data that let PostScript know the size of the dictionary.
+
+<<generate bounding box dictionary>>=
+ print TYPE3 "/BoundingBoxes $total_chars dict def\n";
+ print TYPE3 "BoundingBoxes begin\n";
+ print TYPE3 "/.notdef { 0 0 0 0 } def\n";
+ for($i=0; $i<=256; $i++)
+ {
+ ($_, $llx, $lly, $urx, $ury) = unpack("ai4",$BoundingBox[$i]);
+ print TYPE3 "$Encoding[$i] [ $llx $lly $urx $ury ] def\n"
+ if $_ eq "d";
+ }
+ print TYPE3 "end %BoundingBoxes\n";
+
+
+@ The metrics dictionary is created in way similar to the bounding box
+dictionary. Generally it consists of lines of the form: [[/A 600 def]]
+where the number is the difference urx-llx. As usual we must first
+output some book-keeping information.
+
+<<generate metrics dictionary>>=
+ print TYPE3 "/Metrics $total_chars dict def\n";
+ print TYPE3 "Metrics begin\n";
+ print TYPE3 "/.notdef 0 def\n";
+ for($i=0; $i<=256; $i++)
+ {
+ ($_, $llx, $lly, $urx, $ury) = unpack("ai4",$BoundingBox[$i]);
+ $diff = $urx - $llx;
+ print TYPE3 "$Encoding[$i] $diff def\n" if $_ eq "d";
+ }
+ print TYPE3 "end %Metrics\n";
+
+
+@ Generating the CharProcs dictionary involves the extraction of
+the PostScript code from the various EPSF files. Moreover, we must
+be careful to avoid extracting comments and to delete the keyword
+[[showpage]] from the source code. Both, operations are getting done
+by making use of the regular expression facilities and operators that
+Perl provide. Apart from that we generation process is similar to
+the previous ones. First, we generate some standard code and then
+the PostScript code for each character. Please note, that after
+initial experimentation I have found that METAPOST generates
+a lot of strange [[setgray]] commands which actually confuse a
+PostScript interpreter, so the program eliminates all such commands.
+
+<<generate CharProcs dictionary>>=
+ print TYPE3 "/CharProcs $total_chars dict def\n";
+ print TYPE3 "CharProcs begin\n";
+ print TYPE3 "/.notdef { } def\n";
+ for($i=0; $i<=256; $i++)
+ {
+ $_ = unpack("ai4", $BoundingBox[$i]);
+ if ($_ eq "d")
+ {
+ open(CHAR, "$MFfile.$i")||
+ die "Can't open file $MFfile.$i\n";
+ $code = ""; #"100 100 scale\n";
+ while (<CHAR>)
+ {
+ $code .= $_ if $_ !~ /^%/;
+ }
+ close CHAR;
+ $code =~ s/showpage\n*//mg; #eliminate showpage
+ $code =~ s/\d setgray//mg; #eliminate setgray
+ $code =~ s/(\d*)\.\d+/$1/mg; #chop decimal digits
+ print TYPE3 $Encoding[$i], " { %\n";
+ if ($eofill)
+ {
+ <<Manipulate fills and newpaths>>
+ }
+ else
+ {
+ print TYPE3 $code;
+ }
+ print TYPE3 "} bind def\n";
+ }
+ }
+ print TYPE3 "end %CharProcs\n";
+
+@ In the [[eofill]] mode, we eliminate <b>newpath</b> calls and
+<b>fill</b> calls that are not following <b>gsave</b>.
+And in the end we call eofill.
+<<Manipulate fills and newpaths>>=
+$code =~ s/gsave fill/GSAVE FILL/mg; # save for soon restore
+$code =~ s/fill//mg; # eliminate fill
+$code =~ s/newpath//mg; # eliminate fill
+$code =~ s/GSAVE FILL/gsave fill/mg; # restore
+print TYPE3 $code, "eofill\n";
+
+@ Procedure [[BuildGlyph]] is very important as it defines the way
+PostScript will be able to use the font. The generated code is
+pretty standard.
+
+<<generate BuildGlyph procedure>>=
+ print TYPE3 <<BUILDGLYPH;
+ /BuildGlyph {
+ exch
+ begin
+ dup
+ Metrics exch get % get x displacement
+ 0 % set y displacement
+ 2 index
+ BoundingBoxes
+ exch get aload pop
+ setcachedevice
+ CharProcs exch get
+ exec
+ fill
+ end
+ } def
+ currentdict
+end
+/$MFfile exch definefont
+pop
+BUILDGLYPH
+close TYPE3;
+
+@ Now that we are done we must free some space on our hard disks, unless
+of course the user has decided the opposite. In case we are allowed to free
+space, we remove all the EPSF files, the log file and the TFM file, leaving
+only the Type 3 font file.
+
+<<Delete unnecessary files>>=
+ if (!$nodel)
+ {
+ unlink @EPSFs;
+ unlink "$MFfile.log", "$MFfile.tfm";
+ }
+
+@ <b><h2>Acknowledgments</h2></b><br>
+John Hobby (the creator of METAPOST) and Yotam Medini
+had helped me in the development phase and the debugging phase
+correspondingly. Many thanks to both of you!