diff options
Diffstat (limited to 'info/digests/texhax/txh/kesner.txh')
-rw-r--r-- | info/digests/texhax/txh/kesner.txh | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/info/digests/texhax/txh/kesner.txh b/info/digests/texhax/txh/kesner.txh new file mode 100644 index 0000000000..3beb36bc04 --- /dev/null +++ b/info/digests/texhax/txh/kesner.txh @@ -0,0 +1,475 @@ +Subject: Hershey fonts + +This submission is being sent in response to a question in texhax [#70]. +I (jok@gpu.utcs.toronto.edu) am posting this submission for my father, Oliver. +Consequently, everything after this paragraph is written by him. I will +accept any responses and forward them to him. His interest in TeX +revolves around multi-lingual (hobby) desktop publishing. + +Hershey fonts for the IBM PC are available from SoftCraft, Inc., and from +Austin Code Works. The SoftCraft set consists of four separate databases: + HERSHEY.CHR 1594 characters + ORIENT.CHR 758 char. + PERSIAN.CHR 135 char. + HEBREW.CHR 49 char. +The HERSHEY.CHR database includes, besides several Roman typefaces, Greek, +Russian, German Fraktur, and a variety of graphic symbols; the ORIENT.CHR +database has hiragana, katakana, and 623 kanji characters. + +The format of the SoftCraft Hershey databases is given in their "Font Editing: +EFONT/CFONT User's Manual" on p. A5-2. Using this description, I wrote the +following Turbo Pascal 4.0 program to generate METAFONT source code from the +Hershey plotter directives: + +HERSHEY.PAS +----------- +{$R-} {Range checking off} +{$B-} {Short-circuit Boolean evaluation} +{$S-} {Stack checking off} +{$I+} {I/O checking on} +{$N-} {Numeric coprocessor absent} +{$M 65500, 16384, 655360} {Turbo 3 default stack and heap} + +program Hershey; {generates METAFONT source code from a Hershey character + database in SoftCraft format} +const + NMax = 157; {maximum number of plotter pen movement commands for one + character in the databases} + PenUp = $4000; + EndOfChar = 0; +var + H : file of integer; {Hershey database input} + Log : text; {METAFONT source output} + Code, Depth, EndChar, Height, I, J, K, N, StartChar, Width, XMax, XMin, Y0, + YMax, YMin : integer; + XY : array[0..NMax] of integer; {(x, y) coordinates} + Z : array[1..NMax] of byte; {METAFONT variables} + Database : string[7]; {database filename without extension} + +procedure ReadH; {reads a plotter directive from the input file} +begin + if Eof(H) then + begin + Writeln('End of file at char = ', Code); + Close(H); + Close(Log); + Halt; + end; + Inc(N); + Read(H, XY[N]); +end; {ReadH} + +begin + if ParamCount <> 3 then + begin + Writeln('Usage: HERSHEY database start end'); + Halt; + end; + Database := ParamStr(1); + for Code := 1 to 7 do + Database[Code] := UpCase(Database[Code]); + Val(ParamStr(2), StartChar, Code); + if Code <> 0 then + begin + Writeln('Starting character not an integer'); + Halt; + end; + Val(ParamStr(3), EndChar, Code); + if Code <> 0 then + begin + Writeln('Ending character not an integer'); + Halt; + end; + Assign(H, Database + '.CHR'); + Reset(H); + Assign(Log, Database + '.LOG'); + Rewrite(Log); + Writeln(Log, '% ', Database + '.CHR ', StartChar, ' to ', EndChar); + for Code := 0 to StartChar do + begin + N := -1; + repeat + ReadH; + until XY[N] = EndOfChar; + end; {skip forward to specified start character} + Z[1] := 1; + for Code := StartChar to EndChar do + begin + Writeln(Log); + Writeln(Log, 'cmchar "', Database, ' ', Code, '";'); + N := -1; + ReadH; {the width bytes} + XMin := Lo(XY[0]); {minimum x coordinate} + XMax := Hi(XY[0]); {maximum x coordinate} + Width := XMax - XMin; {width of character} + Y0 := 73; {default y bias} + if Database = 'HERSHEY' then + case Code of + 0..88: Y0 := 68; + 397..672: Y0 := 70; + end; + {Find minimum and maximum y values.} + YMax := 0; + YMin := 256; + repeat + ReadH; + if (XY[N] <> PenUp) and (XY[N] <> EndOfChar) then + begin + if Hi(XY[N]) > YMax then + YMax := Hi(XY[N]); + if Hi(XY[N]) < YMin then + YMin := Hi(XY[N]); + end; {if a real coordinate} + until XY[N] = EndOfChar; + Height := Y0 - YMin; + if YMax > Y0 then + Depth := YMax - Y0 + else + Depth := 0; + Writeln(Log, 'beginchar(', Code mod 128, ', ', Width, 'u#, ', Height, + 'u#, ', Depth, 'u#);'); + Writeln(Log, 'adjust_fit(0, 0);'); + Writeln(Log, 'pickup plotter_pen;'); + for I := 2 to Pred(N) do + begin {enumerate unique coordinates} + Z[I] := 0; + if XY[I] <> PenUp then + begin + for J := Pred(I) downto 1 do + if XY[I] = XY[J] then + Z[I] := J; + if Z[I] = 0 then + Z[I] := I; + end; + end; + for I := 1 to Pred(N) do + if Z[I] = I then + Writeln(Log, 'z', I, ' = (', Lo(XY[I]) - XMin, 'u, ', Y0 - Hi(XY[I]), + 'u);'); + I := 0; + J := 1; + repeat + Inc(I); + if (XY[I] = PenUp) or (XY[I] = EndOfChar) then + begin + case I - J of {number of points joined by consecutive line segments} + 0: ; + 1: Writeln(Log, 'drawdot z', Z[J], ';'); + 2: if Z[J] = Z[Succ(J)] then + Writeln(Log, 'drawdot z', Z[J], ';') + else + Writeln(Log, 'draw z', Z[J], '--z', Z[Succ(J)], ';'); + else + begin + Write(Log, 'draw z', Z[J]); + for K := Succ(J) to Pred(I) do + Write(Log, '--z', Z[K]); + Writeln(Log, ';'); + end; {3 or more} + end; {case} + J := Succ(I); + end; {if a real coordinate} + until I = N; + Writeln(Log, 'endchar;'); + end; {specified range of characters} + Close(H); + Close(Log); +end. + +As a test case I used the DOS command + hershey orient 0 1 +to produce the following output: + +ORIENT.LOG +---------- +% ORIENT.CHR 0 to 1 + +cmchar "ORIENT 0"; +beginchar(0, 27u#, 12u#, 0u#); +adjust_fit(0, 0); +pickup plotter_pen; +z1 = (3u, 10u); +z2 = (25u, 10u); +z3 = (22u, 12u); +z4 = (20u, 10u); +z7 = (23u, 11u); +draw z1--z2--z3--z4; +draw z4--z7; +endchar; + +cmchar "ORIENT 1"; +beginchar(1, 27u#, 22u#, 0u#); +adjust_fit(0, 0); +pickup plotter_pen; +z1 = (3u, 20u); +z2 = (25u, 20u); +z3 = (23u, 22u); +z4 = (21u, 20u); +z7 = (24u, 21u); +z9 = (13u, 20u); +z10 = (12u, 13u); +z11 = (11u, 9u); +z12 = (10u, 7u); +z13 = (8u, 4u); +z14 = (6u, 2u); +z15 = (3u, 0u); +z17 = (14u, 20u); +z18 = (13u, 13u); +z19 = (12u, 9u); +z20 = (10u, 5u); +z21 = (8u, 3u); +z22 = (5u, 1u); +z25 = (13u, 14u); +z26 = (21u, 14u); +z28 = (20u, 14u); +z29 = (21u, 15u); +z30 = (23u, 14u); +z31 = (21u, 11u); +z34 = (20u, 7u); +z35 = (19u, 3u); +z36 = (18u, 2u); +z37 = (16u, 1u); +z38 = (13u, 2u); +z40 = (19u, 2u); +z41 = (18u, 1u); +z42 = (17u, 1u); +z44 = (22u, 14u); +z45 = (21u, 7u); +z46 = (20u, 3u); +z47 = (19u, 1u); +z48 = (18u, 0u); +z49 = (17u, 0u); +draw z1--z2--z3--z4; +draw z4--z7; +draw z9--z10--z11--z12--z13--z14--z15; +draw z17--z18--z19--z20--z21--z22--z15; +draw z25--z26; +draw z28--z29--z30--z31; +draw z26--z34--z35--z36--z37--z38; +draw z40--z41--z42; +draw z44--z45--z46--z47--z48--z49--z37; +endchar; + + +I used the following METAFONT parameter file: + +ORIENT.MF +--------- +% This is ORIENT.MF in text format, as of May 6, 1988. +% Based on Computer Modern Roman 10 point +if unknown cmbase: input cmbase fi + +font_identifier:="ORIENT"; font_size 10pt#; + +u#:=20/36pt#; % unit width +width_adj#:=0pt#; % width adjustment for certain characters +serif_fit#:=0pt#; % extra sidebar near lowercase serifs +cap_serif_fit#:=5/36pt#; % extra sidebar near uppercase serifs +letter_fit#:=0pt#; % extra space added to all sidebars + +body_height#:=270/36pt#; % height of tallest characters +asc_height#:=250/36pt#; % height of lowercase ascenders +cap_height#:=246/36pt#; % height of caps +fig_height#:=232/36pt#; % height of numerals +x_height#:=155/36pt#; % height of lowercase without ascenders +math_axis#:=90/36pt#; % axis of symmetry for math symbols +bar_height#:=87/36pt#; % height of crossbar in lowercase e +comma_depth#:=70/36pt#; % depth of comma below baseline +desc_depth#:=70/36pt#; % depth of lowercase descenders + +crisp#:=0pt#; % diameter of serif corners +tiny#:=8/36pt#; % diameter of rounded corners +fine#:=7/36pt#; % diameter of sharply rounded corners +thin_join#:=7/36pt#; % width of extrafine details +hair#:=9/36pt#; % lowercase hairline breadth +stem#:=25/36pt#; % lowercase stem breadth +curve#:=30/36pt#; % lowercase curve breadth +ess#:=27/36pt#; % breadth in middle of lowercase s +flare#:=33/36pt#; % diameter of bulbs or breadth of terminals +dot_size#:=38/36pt#; % diameter of dots +cap_hair#:=11/36pt#; % uppercase hairline breadth +cap_stem#:=32/36pt#; % uppercase stem breadth +cap_curve#:=37/36pt#; % uppercase curve breadth +cap_ess#:=35/36pt#; % breadth in middle of uppercase s +rule_thickness#:=.4pt#; % thickness of lines in math symbols + +dish#:=1/36pt#; % amount erased at top or bottom of serifs +bracket#:=20/36pt#; % vertical distance from serif base to tangent +jut#:=28/36pt#; % protrusion of lowercase serifs +cap_jut#:=37/36pt#; % protrusion of uppercase serifs +beak_jut#:=10/36pt#; % horizontal protrusion of beak serifs +beak#:=70/36pt#; % vertical protrusion of beak serifs +vair#:=8/36pt#; % vertical diameter of hairlines +notch_cut#:=10pt#; % maximum breadth above or below notches +bar#:=11/36pt#; % lowercase bar thickness +slab#:=11/36pt#; % serif and arm thickness +cap_bar#:=11/36pt#; % uppercase bar thickness +cap_band#:=11/36pt#; % uppercase thickness above/below lobes +cap_notch_cut#:=10pt#; % max breadth above/below uppercase notches +serif_drop#:=4/36pt#; % vertical drop of sloped serifs +stem_corr#:=1/36pt#; % for small refinements of stem breadth +vair_corr#:=1/36pt#; % for small refinements of hairline height +apex_corr#:=0pt#; % extra width at diagonal junctions + +o#:=8/36pt#; % amount of overshoot for curves +apex_o#:=8/36pt#; % amount of overshoot for diagonal junctions + +slant:=0; % tilt ratio $(\Delta x/\Delta y)$ +fudge:=1; % factor applied to weights of heavy characters +math_spread:=0; % extra openness of math symbols +superness:=1/sqrt2; % parameter for superellipses +superpull:=1/6; % extra openness inside bowls +beak_darkness:=11/30; % fraction of triangle inside beak serifs +ligs:=2; % level of ligatures to be included + +square_dots:=false; % should dots be square? +hefty:=false; % should we try hard not to be overweight? +serifs:=true; % should serifs and bulbs be attached? +monospace:=false; % should all characters have the same width? +variant_g:=false; % should an italic-style g be used? +low_asterisk:=false; % should the asterisk be centered at the axis? +math_fitting:=false; % should math-mode spacing be used? + +font_coding_scheme:="Hershey ORIENT.CHR"; + +mode_setup; font_setup; + +px#:=rule_thickness#; % horizontal thickness of pen +py#:=.9px#; % vertical pen thickness +define_blacker_pixels(px,py); +pickup pencircle xscaled px yscaled py; +plotter_pen:=savepen; +input \ff\orient.log + +font_slant slant; font_x_height x_height#; +if monospace: font_normal_space 9u#; % no stretching or shrinking + font_quad 18u#; + font_extra_space 9u#; +else: font_normal_space 6u#+2letter_fit#; + font_normal_stretch 3u#; font_normal_shrink 2u#; + font_quad 18u#+4letter_fit#; + font_extra_space 2u#; fi +bye. + +The following sequence of DOS commands + cd\ff + hershey orient 0 127 + cd\pcmf + mf &cm \mode=epson; \mag=magstep 0; input orient /a=99/t +produced ORIENT.240 and ORIENT.TFM in \pcmf for my Epson FX-85 printer, +containing the first 128 characters of ORIENT.CHR. + +The characters in the Austin Code Works Hershey database are numbered 1--4326, +with gaps, for a total of 1,377 different alphabetic and graphic characters. +The format is described in Norman M. Wolcott and Joseph Hilsenrath, "A +Contribution to Computer Typesetting Techniques: Tables of Coordinates for +Hershey's Repertory of Occidental Type Fonts and Graphic Symbols," U.S. +Department of Commerce, National Bureau of Standards, April 1976. In any case, +the following Turbo Pascal 4.0 program converts the ACW Hershey database to +SoftCraft format for further processing. + +ACWTOSC.PAS +----------- +{$R-} {Range checking off} +{$B-} {Short-circuit Boolean evaluation} +{$S-} {Stack checking off} +{$I+} {I/O checking on} +{$N-} {No numeric coprocessor} +{$M 65500, 16384, 655360} {Turbo 3 default stack and heap} + +program ACWtoSC; {converts the Hershey font tables distributed by The Austin + Code Works to the format expected by the Cfont program of SoftCraft, Inc.} +const + PenUp : integer = $4000; +type + S3 = string[3]; +var + Buf1 : array[1..$2000] of char; + F1 : text; + H : file of integer; + L1 : string[80]; + Fn : array[1..2] of string[64]; + Code, I, L, M, XY : integer; + X, Y : array[1..144] of integer; + Eoc : boolean; + +function V(S : S3) : integer; +var + I : integer; +begin + Val(S, I, Code); + if (Code <> 0) or ((I < -49) and (I <> -64)) or (I > 49) then + begin + Writeln(L1); + Writeln('Code = ', Code); + Halt(3); + end; + V := I; +end; + +begin + if ParamCount <> 2 then + begin + Writeln('Usage: ACWTOSC file1 file2'); + Halt(3); + end; + for L := 1 to 2 do + begin + Fn[L] := ParamStr(L); + for M := 1 to Length(Fn[L]) do + Fn[L][M] := UpCase(Fn[L][M]); + end; + Assign(F1, Fn[1]); + SetTextBuf(F1, Buf1); + {$I-} Reset(F1); {$I+} + if IOResult <> 0 then + begin + Writeln('Cannot open ', Fn[1]); + Halt(3); + end; + Assign(H, Fn[2]); + {$I-} Rewrite(H); {$I+} + if IOResult <> 0 then + begin + Writeln('Cannot open ', Fn[2]); + Close(F1); + Halt(3); + end; + while not Eof(F1) do + begin + Readln(F1, L1); + if Copy(L1, 5, 1) <> ' ' then + begin + M := 0; + Eoc := false; + end; + L := 0; + repeat + Inc(L); + Inc(M); + X[M] := V(Copy(L1, 8 * L + 1, 3)); + Y[M] := V(Copy(L1, 8 * L + 5, 3)); + if (X[M] = -64) and (Y[M] = -64) then + begin + Eoc := true; + Write(H, Code); {two bytes of zeros before each character} + XY := 256 * (Y[1] + 64) + X[1] + 64; {width of character} + Write(H, XY); + for I := 2 to Pred(M) do + if X[I] = -64 then + Write(H, PenUp) + else + begin + XY := 256 * (73 + Y[I]) + X[I] + 64; + Write(H, XY); + end; + end; + until (L = 8) or Eoc; + end; + Write(H, Code); {two bytes of zeros at end of file} + Close(F1); + Close(H); +end. + +------- + |