| H | Hershey's Font | Lab Report |
| One of the "vector characters" in
the Hershey Font
Windows 2000 / Delphi 7 Version |
||
![]() |
||
|
|
||
| Red Hat 7.2 Linux / Kylix 3 Version | ||
![]() |
||
Purpose
The purpose of this Delphi/Kylix project is to demonstrate how to manipulate
the data and display the characters in the original Hershey font files.
Background
The "Hershey Fonts" were developed in the 1960s by Dr.
A. V. Hershey at the U.S. Naval Weapons Laboratory.
The U.S. National Bureau of Standards published the 173-page Special Publication 424 in 1976: A Contribution To Computer Typesetting Techniques: Tables of Coordinates for Hershey's Repertory of Occidental Type Fonts and Graphic Symbols. The publication listed all the data points and showed the graphics for each character. The data were available on magnetic tape as recently as the mid-1980s for $500 from the National Technical Information Service! A few years later the nearly 500 KB data file could be found on the Internet -- but it's somewhat difficult to find today.
There were 1377 characters in the original Hershey set, each of which is assigned a number between 1 and 3926. The characters are described as uniplex, duplex, or triplex according to the number of parallel strokes used in the construction of the character. Three sizes of characters are available: the principal or normal size (21 raster units high, em = 32), the indexical size (13 raster units high, em = 21), and the cartographic size (9 raster units high).
In the Hershey system, characters are drawn by connecting lines between successive (x, y) coordinates pairs. The coordinates of each character are given in raster coordinates, which are integers ranging from 49 to -49. A useful quantity is the printer's em, or the distance between the bottoms of two successive lines of close packed text.
The data are organized in the following way: The first column is the character number, the first pair of numbers separated by colons (:) are the left and right boundaries of the character in raster coordinates, and succeeding pairs of numbers set off by colons denote the (x,y) set for that character. An (x,y) coordinate pair of (-64, 0) indicates that the pen is lifted at that point in the character; a coordinate pair of (-64, -64) indicates that the end of the character has been reached.
Here is what the data for the first three characters look like:
1 : -5 5: 0 -5: -4 4:-64 0: 0 -5: 4 4:-64 0: -2 1:
: 2 1:-64 -64:
2 : -5 5: -3 -5: -3 4:-64 0: -3 -5: 1 -5: 3 -4: 3 -2:
: 1 -1:-64 0: -3 -1: 1 -1: 3 0: 3 3: 1 4: -3 4:
:-64 -64:
3 : -5 6: 4 -4: 2 -5: 0 -5: -2 -4: -3 -2: -3 1: -2 3:
: 0 4: 2 4: 4 3:-64 -64:
|
Materials and Equipment
Software Requirements
Windows 95/98/2000 Linux Delphi 3/4/5/6/7 (to recompile) Kylix 3 (to recompile) Hershey.EXE Hershey excutable Hershey.DAT
Hardware Requirements
800-by-600 video display
Procedure
1. Start the Windows or Linux executable, Hershey.
2. In the list box at the left of the screen, scroll up or down and select the desired Hershey symbol -- or just step through one-by-one to view them all. When a Hershey character is selected, the "Points" memo box shows the data for that symbol.
3. If desired, change the scale factor, or the rotation angle, for the selected character.
4. Press Show Table button to view sections of the Hershey font.
Discussion
The original data files, which were combined into a single Hershey.DAT file, were read in two steps in the FormCreate method. The first step involved reading the "Raw" data from the original file. The second step combined lines for the same symbol into a single line in the ListBoxHershey list.
|
Loading Hershey.DAT into ListBoxHershey |
|
procedure
TFormHershey.FormCreate(Sender: TObject); VAR Filename: TFilename; i : INTEGER; Raw : TStringList; s : STRING; begin // Don't allow form to be resized WITH FormHershey.Constraints DO BEGIN MaxHeight := Height; MaxWidth := Width; MinHeight := Height; MinWidth := Width END; Hershey := TStringList.Create; Filename := ExtractFilePath(ParamStr(0)) + 'Hershey.DAT'; IF FileExists(Filename) Screen.Cursor :=
crHourGlass; Raw
:= TStringList.Create;
// Reduce each character to one line
s := Raw[i]
ListBoxHershey.ItemIndex := 0;
FINALLY FINALLY // Avoid
SpinEditScaleChanged being called during END |
Once the table is loaded, the first symbol in the list is automatically selected. Whenever a symbol is selected, or when its scaling factor or rotation angle is changed, the HersheyChange method is called:
|
Changing a selected symbol, or change in scaling or rotation of a symbol |
procedure TFormHershey.ListBoxHersheyClick(Sender: TObject); begin HersheyChange(ulUpdateList); end; procedure TFormHershey.UpdateHersheyLook(Sender: TObject); begin // This appraoch avoids unnecessry updates and flicker // of MemoCharacter HersheyChange(ulDoNotUpdateList) end; |
The HersheyChange method updates the display of a single Hershey symbol:
| Displaying single Hershey symbol |
PROCEDURE TFormHershey.HersheyChange(CONST NewPointList: TUpdateList);
TYPE
TPenMode = (pmUp, pmDown);
VAR
alpha : Double;
Bitmap : TBitmap;
BoundaryLeft : INTEGER;
BoundaryRight: INTEGER;
CosAlpha : Double;
index : STRING;
penmode : TPenMode;
s : STRING;
Scale : INTEGER;
SinAlpha : Double;
t : STRING;
x : INTEGER;
xMidPoint : INTEGER;
xOld : INTEGER;
xPrime : INTEGER;
xSave : INTEGER;
y : INTEGER;
yOld : INTEGER;
yMidPoint : INTEGER;
yPrime : INTEGER;
begin xOld := 0; // avoid compiler warning yOld := 0; xMidPoint := Image.Width DIV 2; yMidPoint := Image.Height DIV 2; Scale := SpinEditScale.Value; IF NewPointList = ulUpdateList THEN MemoCharacter.Lines.Clear; s := ListBoxHershey.Items[ListBoxHershey.ItemIndex]; index := Trim( COPY(s,1,7) ); Delete(s,1,8); BoundaryLeft := StrToInt(COPY(s,1,3)); BoundaryRight := StrToInt(COPY(s,5,3)); Delete(s,1,8); Bitmap := TBitmap.Create;
TRY
Bitmap.Width := Image.Width;
Bitmap.Height := Image.Height;
Bitmap.Canvas.Font.Name := 'Arial';
Bitmap.Canvas.Font.Height := MulDiv(Image.Height, 12, 100);
Bitmap.Canvas.Font.Style := [fsBold];
Bitmap.Canvas.TextOut(2,2, index);
Bitmap.Canvas.Pen.Color := clSilver;
Bitmap.Canvas.MoveTo(xMidPoint + BoundaryLeft*Scale, yMidPoint - 5*Scale);
Bitmap.Canvas.LineTo(xMidPoint + BoundaryLeft*Scale, yMidPoint + 5*Scale);
Bitmap.Canvas.MoveTo(xMidPoint + BoundaryRight*Scale, yMidPoint - 5*Scale);
Bitmap.Canvas.LineTo(xMidPoint + BoundaryRight*Scale, yMidPoint + 5*Scale);
penmode := pmUp;
WHILE( LENGTH(s) > 0 ) DO
BEGIN
x := StrToInt(COPY(s,1,3));
y := StrToInt(COPY(s,5,3));
IF NewPointList = ulUpdateList
THEN MemoCharacter.Lines.Add( '(' + IntToStr(x) + ', ' + IntToStr(y) + ')' );
// Rotate figure // As suggested by Jacques Oberto, rotation of these figures is easy
// since the center of the figure is the origin.
t := 'Rotation = ' + IntToStr(TrackBarRotation.Position) +
' degree';
IF TrackBarRotation.Position <> 1
THEN t := t + 's';
LabelRotate.Caption := t; // use "-" here to force counterclockwise rotation
alpha := -TrackBarRotation.Position * PI / 180; {degrees to radians}
// Could use SinCos function in math unit instead of separate calls
SinAlpha := Sin(alpha);
CosAlpha := Cos(alpha);
// See Rotation Math background xSave := x; xPrime := Round(xSave*CosAlpha - y*SinAlpha); yPrime := Round(xSave*SinAlpha + y*CosAlpha); // Rescale and translate figure
xPrime := xMidPoint + Scale*xPrime;
yPrime := yMidPoint + Scale*yPrime;
Bitmap.Canvas.Pen.Color := clBlue;
Bitmap.Canvas.Brush.Color := clBlue;
// "-64" is tag for pen up
IF (x = -64) OR (y = -64)
THEN penmode := pmUp
ELSE BEGIN
IF penmode = pmUp
THEN BEGIN
Bitmap.Canvas.MoveTo(xPrime, yPrime);
penmode := pmDown
END
ELSE BEGIN
IF CheckBoxShowDots.Checked
THEN BEGIN
Bitmap.Canvas.Ellipse(xOld-2, yOld-2, xOld+2, yOld+2);
Bitmap.Canvas.Ellipse(xPrime-2, yPrime-2, xPrime+2, yPrime+2);
Bitmap.Canvas.MoveTo(xOld, yOld)
END;
Bitmap.Canvas.LineTo(xPrime, yPrime);
END
END; xOld := xPrime;
yOld := yPrime;
Delete(s,1,8)
END;
Image.Picture.Graphic := Bitmap;
FINALLY
Bitmap.Free
END
END {HersheyChange};
|
The Show Table button displays a separate screen with all the Hershey symbols shown in eight tables. See the source code for how this is done.
Conversion from Delphi 3 to Kylix was not completely straightforward (but this was only my second Delphi-to-Kylix conversion).
The units needed by the VCL version include:
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, Spin, ComCtrls;
The units needed by the CLX version include:
SysUtils, Types, Classes, Variants, QGraphics, QControls, QForms, QDialogs,
QStdCtrls, QExtCtrls, QComCtrls;
Note that many of the VCL units have "Q" corresponding names in CLX.
I encountered and fixed these problems in the conversion:
1. I observed that Kylix forms needed to have "Scaled = FALSE" to get the same screen look as "Scaled = TRUE" in Delphi. This is confusing. Also be sure to set AutoScroll=FALSE -- see CLX Form Portability.
2. The Application icon must be set as a Form property in Kylix. In Delphi this also works but I had learned to set it in Delphi via Project | Options | Application | Icon.
3. I had problems getting Kylix to honor the Border Icons (maximize = FALSE) and Border Style ("single"), but they worked after resetting them a several times.
4. The TListBox showing the list of Hershey symbol codes had a horizontal scroll bar in Kylix, but not in Delphi.
5. The OnChange of the TSpinEdit did not survive the transfer from Delphi to Kylix. I had to re-establish this method.
6. Before converting to Kylix 1 from Delphi 3, I had to compile the program in Delphi 5 and request "Text DFM". (I'm not sure why this was not true in converting the SimpleBarChart project.)
Additional problems encountered in K3/D7 upgrade:
1. The SpinEditScale.OnChanged method is firing too soon during initialization -- so don't even define method until near end of form create.
2. A problem was observed in getting rid of a horizontal scollbar with ListBoxHershey due to variability in scaling of components. To avoid this problem, I created a e form global Hershey TStringList and kept complete info there instead of the ListBoxHershey. This allowed getting rid of owner drawing of ListBoxHershey.
Conclusions
The Hershey font was an interesting historical vector font, which
provided an excuse to study the conversion of a Delphi project to Kylix under
Linux.
Also see:
Jim Buzbee's Hershey Font Page, www.batbox.org/font.html
Hershey Fonts: http://coder.com/creations/banner/fonts/hershey.html
Keywords
Hershey Font, vector fonts, rotation, scaling, VCL, CLX, TStringList, TListBox,
TSpinEdit, Application Icon, Delphi 3/4/5/6/7, Kylix 1/2/3, Linux
Download
Delphi 3/4/5/6/7 VCL Source and EXE:
HersheyVCL.zip
(2227 KB) zip file includes Hershey.DAT file) [older version]
Delphi 7 CLX Source and executable: HersheyCLX.zip
(301 KB) includes Hershey.DAT file [newer version]
See notes about CLX
deployment to get the needed Windows DLL.
Kylix 3 CLX Source and executable: Hershey.tar.gz
(344 KB) includes Hershey.DAT file
In Linux to extract files: gunzip <
Hershey.tar.gz | tar xvf -
See Kylix
Deployment Notes for "Hello World" for deployment of CLX
applications in Linux.
Updated 25 Feb 2003
since 10 May 2001