PrintFontsImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last Changed: Maureen Stone March 18, 1985 3:58:23 pm PST
Written by: Maureen Stone May 7, 1985 5:22:04 pm PDT
DIRECTORY
Imager,
ImagerBasic USING [PixelArray, PathMapType],
ImagerTransform USING [InverseTransform, Contents, Transform],
ImagerPD USING[PDFileDescription, PDFileDescriptionRep, Hornet],
PDFileFormat,
Real USING [Fix],
SampledColors USING[bitmap, DrawImage],
Font USING [CreateScaled, FONT, Box, FormattingBox],
Rope USING [ROPE, Cat, Substr],
Convert USING [RopeFromInt],
FS USING [ExpandName, ComponentPositions, StreamOpen],
IO USING [time, rope, real, int, PutFR, Close, PutRope, STREAM],
ImagerPrivate,
BasicTime,
PrintFonts,
SDtoSF USING[PathToStream],
PrintFontsPrivate;
PrintFontsImpl: CEDAR PROGRAM
IMPORTS Imager, SampledColors, Rope, ImagerTransform, Real, Font, Convert, ImagerPD, FS, IO, BasicTime, PrintFontsPrivate, SDtoSF
EXPORTS PrintFonts = BEGIN OPEN PrintFonts;
ROPE: TYPE = Rope.ROPE;
PrivateFont: TYPE = PrintFontsPrivate.PrivateFont;
for debugging
doChars: BOOLEANTRUE;
currentWD: ROPE ← "///PD/";
Prints all the characters in the file. SD and SF fonts do not inherently contain a pointSize so the pointSize parameter is necessary. Size is in output coordinates as above.
PrintSFFile: PUBLIC PROC[name: ROPE, device: DeviceType, pointSize, scale: REAL] RETURNS [pd: ROPE] = {
sfFont: PrivateFont;
base, wdir, label, pdFile: ROPE;
devicePts: REAL;
ctx: Imager.Context;
[base, wdir] ← GetName[name];
[ctx, pdFile] ← OpenPD[base, device];
IF pointSize=0 THEN devicePts ← 1 --special for fonts generated "at size`'
ELSE [[devicePts, ]] ← ImagerTransform.Transform[[pointSize, 1],ctx.state.T];
sfFont ← PrintFontsPrivate.LoadSF[Rope.Cat[wdir,base,".sf"], devicePts];
label ← IO.PutFR["%g.sf, scale=%g, time= %g", IO.rope[base], IO.real[scale], IO.time[]];
PrintPages[label, sfFont, device, ctx, scale];
RETURN[pdFile]
};
PrintSDFile: PUBLIC PROC[name: ROPE, device: DeviceType, pointSize, scale: REAL] RETURNS [pd: ROPE] = {
sdFont: PrivateFont;
base, wdir, label, pdFile: ROPE;
devicePts: REAL;
ctx: Imager.Context;
[base, wdir] ← GetName[name];
[ctx, pdFile] ← OpenPD[base, device];
IF pointSize=0 THEN devicePts ← 1 --special for fonts generated "at size`'
ELSE [[devicePts, ]] ← ImagerTransform.Transform[[pointSize, 1],ctx.state.T];
sdFont ← PrintFontsPrivate.LoadSD[Rope.Cat[wdir,base,".sd"], devicePts];
label ← IO.PutFR["%g.sd, scale=%g, time= %g", IO.rope[base], IO.real[scale], IO.time[]];
PrintPages[label, sdFont, device, ctx, scale];
RETURN[pdFile]
};
PrintACFile: PUBLIC PROC[name: ROPE, device: DeviceType, scale: REAL] RETURNS [ROPE] = {
Prints all the characters in the file
acFont: PrivateFont;
base, wdir, label, pdFile: ROPE;
ctx: Imager.Context;
[base, wdir] ← GetName[name];
acFont ← PrintFontsPrivate.LoadAC[Rope.Cat[wdir,base,".ac"]];
[ctx, pdFile] ← OpenPD[base, device];
label ← IO.PutFR["%g.ac, scale=%g, time= %g", IO.rope[base], IO.real[scale], IO.time[]];
PrintPages[label, acFont, device, ctx, scale];
RETURN[pdFile]
};
ScaleSF: PUBLIC PROC [input, output: ROPE, scale: REAL] = {
font: PrintFontsPrivate.PrivateFont;
base, wdir: ROPE;
sfFont: IO.STREAM;
[base, wdir] ← GetName[input];
font ← PrintFontsPrivate.LoadSF[Rope.Cat[wdir,base,".sf"], scale];
[base, wdir] ← GetName[output];
sfFont ← FS.StreamOpen[fileName: Rope.Cat[wdir,base,".sf"], accessOptions: $create, keep: 2];
FOR char: CHAR IN [font.bc..font.ec) DO
PrintFontsPrivate.ScalePathData[font.charRep[char].outline.pathData, scale, scale];
SDtoSF.PathToStream[
dest: sfFont, pathMap: font.charRep[char].outline.pathMap,
pathData: font.charRep[char].outline.pathData,
family: font.family, face: "M R R", charCode: VAL[char],
widthx: font.charRep[char].width, widthy: 0];
ENDLOOP;
IO.PutRope[sfFont, "STOP\n"];
IO.Close[sfFont];
};
PrintPages: PROC[label: ROPE, font: PrivateFont, device: DeviceType, ctx: Imager.Context, scale: REAL] = {
maxH, maxW, gl, gt: REAL ← 0;
areaW, areaH, boxW, boxH: REAL;
nw, nh: INT;
bc, nchars: NAT;
maxW ← font.maxW*scale; --max size a function of scale
maxH ← (font.ascent+font.descent)*scale;
divide the page into characters and captions. Compute how many bits are in the character area and divide it into equal squares big enough for the maximum character size
areaW ← pageW-right-left-5*captions.nwidth; --in points
areaH ← pageH-top-bottom-4*captions.height;
[[boxW, boxH]] ← ImagerTransform.InverseTransform[[maxW, maxH], ctx.state.T]; --in points
boxW ← boxW+8; boxH ← boxH+8;  --add the gridline space plus some white space
nw ← Real.Fix[areaW/boxW]; --determine the count
nh ← Real.Fix[areaH/boxH];
bc ← VAL[font.bc];
nchars ← ORD[font.ec-VAL[bc]];
IF nw*nh=0 THEN ERROR;
IF nchars > nw*nh THEN { -- print multiple pages
page: INT ← 1;
UNTIL nw*nh >= nchars DO
[gl, gt] ← GridAndTitle[ctx, bc, nw, nh, boxW, boxH, IO.PutFR["%g page = %g", IO.rope[label], IO.int[page]]];
PrintChars[ctx, font, VAL[bc], gl, gt, nw, nh, boxW, boxH, scale];
[] ← Imager.SpecialOp[ctx, $NewPage, NIL]; --resets the context
ctx.ScaleT[0.0254/72]; --meters to points
bc ← bc+nw*nh;
nchars ← ORD[font.ec-VAL[bc]];
page ← page+1;
ENDLOOP;
label ← IO.PutFR["%g page = %g", IO.rope[label], IO.int[page]]; --for last page
};
now print last page. May be partial page
IF nw*nh > nchars THEN {nh ← nchars/nw; IF nh*nw<nchars THEN nh ← nh+1};
[gl, gt] ← GridAndTitle[ctx, bc, nw, nh, boxW, boxH, label];
PrintChars[ctx, font, VAL[bc], gl, gt, nw, nh, boxW, boxH, scale];
[] ← Imager.SpecialOp[ctx, $Close, NIL];
};
GetName: PROC[name: ROPE] RETURNS [base: ROPE, wdir: ROPE] = {
full: ROPE;
cp: FS.ComponentPositions;
[full, cp, ] ← FS.ExpandName[name];
base ← Rope.Substr[full, cp.base.start, cp.base.length];
wdir ← Rope.Cat["[",Rope.Substr[full, cp.server.start, cp.server.length], "]<",
Rope.Substr[full, cp.dir.start, cp.dir.length], ">"];
wdir ← Rope.Cat[wdir, Rope.Substr[full, cp.subDirs.start, cp.subDirs.length], ">"];
};
PrintChars: PROC [ctx: Imager.Context, font: PrivateFont, bc: CHAR, gl, gt: REAL, nw, nh: INT, boxW,boxH, scale: REAL] = {
print nw*nh chars, begining at bc
bitsW, bitsH, sx, sy: REAL;
char: CHAR ← bc;
class: ImagerPrivate.Class ← NARROW[ctx.class];
DoRow: PROCIF font.type=raster THEN DoRasterRow ELSE DoOutlineRow;
DoRasterRow: PROC = {
FOR i: INT IN [0..nw) DO
IF font.charRep[char].pixels#NIL THEN {
dx: REAL ← (bitsW-font.charRep[char].width)/2.0; --center it
Imager.TranslateT[ctx, dx, 0];
SampledColors.DrawImage[ctx,font.charRep[char].pixels,SampledColors.bitmap];
Imager.TranslateT[ctx,bitsW-dx,0];
}
ELSE Imager.TranslateT[ctx, bitsW, 0];
char ← char+1;
IF char > font.ec THEN EXIT;
ENDLOOP;
};
DoOutlineRow: PROC = {
DoChar: PROC = {
Imager.ScaleT[ctx,font.pointSize];
class.MaskFill[ctx,
font.charRep[char].outline.pathMap, font.charRep[char].outline.pathData];
};
FOR i: INT IN [0..nw) DO
IF font.charRep[char].outline#NIL THEN {
dx: REAL ← (bitsW-font.charRep[char].width)/2.0; --center it
Imager.TranslateT[ctx, dx, 0];
Imager.DoSaveAll[ctx, DoChar];
Imager.TranslateT[ctx,bitsW-dx,0];
}
ELSE Imager.TranslateT[ctx, bitsW, 0];
char ← char+1;
IF char > font.ec THEN EXIT;
ENDLOOP;
};
in points, translate to the upper right of the grid, include the gridwidth and some whitespace
Imager.TranslateT[ctx, gl+1, gt-2-3];
We need to think in scaled bits for the pixel arrays. Convert the transformation system to scaled bits, the stepping quantities to unscaled bits
[[sx, , , ,sy, ]] ← ImagerTransform.Contents[ctx.state.T];
bitsW ← sx*boxW/scale; 
bitsH ← sy*boxH/scale;
Imager.Scale2T[ctx, scale/sx, scale/sy]; --Convert to scaled bits
Imager.TranslateT[ctx, 0, -font.ascent]; --drop down by the maximum ascent
FOR i: INT IN [0..nh) DO
Imager.DoSaveAll[ctx, DoRow];
IF char > font.ec THEN EXIT;
Imager.TranslateT[ctx, 0, -bitsH];
ENDLOOP;
};
OpenPD: PROC[base: ROPE, device: DeviceType] RETURNS [ctx: Imager.Context, name: ROPE] = {
pdDescr: ImagerPD.PDFileDescription;
name ← SELECT device FROM
hornet => Rope.Cat[currentWD, base, "-ht.pd"],
platemaker => Rope.Cat[currentWD, base, "-pm.pd"],
versatec => Rope.Cat[currentWD, base, "-vtec.pd"],
ENDCASE => ERROR;
pdDescr ← SELECT device FROM
hornet => ImagerPD.Hornet[name],
platemaker => PlatemakerPD[name],
versatec => VersatecPD[name],
ENDCASE => ERROR;
ctx ← Imager.Create[$PD, pdDescr];
ctx.ScaleT[0.0254/72]; --meters to points
};
GridAndTitle: PROC [ctx: Imager.Context, first: NAT, nw, nh: INT, boxW,boxH: REAL, label: ROPE] RETURNS [gridLeft, gridTop: REAL]= {
Write the captions and gridlines. Ctx coordinate system is in points.
gw,gh: REAL;
val: NAT;
showVal: PROC = {
Imager.ShowCharacters[ctx,Convert.RopeFromInt[from: val, base: 10, showRadix: FALSE]]};
Imager.SetFont[ctx, captions.font];
Imager.SetXY[ctx,[left, bottom]];
Imager.ShowCharacters[ctx,label]; --font name label
grid
gridLeft ← left+5*captions.nwidth;
gridTop ← pageH-top-2*captions.height;
gw ← nw*boxW+2;
gh ← nh*boxH;
FOR i: INT IN [0..nh] DO
Imager.MaskRectangle[ctx,gridLeft, gridTop-i*boxH, gw, 2]; ENDLOOP;
FOR i: INT IN [0..nw] DO
Imager.MaskRectangle[ctx,gridLeft+i*boxW, gridTop-gh, 2, gh]; ENDLOOP;
Imager.SetXY[ctx,[gridLeft+boxW/2-captions.nwidth, gridTop+captions.height]];
val ← 0;
FOR i: INT IN [0..nw) DO--top line
Imager.DoSaveAll[ctx,showVal];
Imager.SetXYRel[ctx,[boxW, 0]];
val ← val+1;
ENDLOOP;
Imager.SetXY[ctx,[left, gridTop-boxH/2-captions.height/2]];
val ← first;
FOR i: INT IN [0..nh) DO
Imager.DoSaveAll[ctx,showVal];
Imager.SetXYRel[ctx,[0, -boxH]];
val ← val+nw;
ENDLOOP;
RETURN[gridLeft, gridTop]
};
PlatemakerPD: PROC[name: ROPE] RETURNS [ImagerPD.PDFileDescription] = {
param: ImagerPD.PDFileDescription ← NEW[ImagerPD.PDFileDescriptionRep ← PlatemakerTemplate];
param.fileName ← name;
RETURN[param];
};
VersatecPD: PROC[name: ROPE] RETURNS [ImagerPD.PDFileDescription] = {
param: ImagerPD.PDFileDescription ← NEW[ImagerPD.PDFileDescriptionRep ← VersatecTemplate];
param.fileName ← name;
RETURN[param];
};
PlatemakerTemplate: ImagerPD.PDFileDescriptionRep ← [
fileName: NIL,
deviceCode: mig,
sResolution: 1200,
fResolution: 1200,
imageSSize: 13200,
imageFSize: 10200,
nColors: 1,
bandSSize: 16,
maxLoadWords: 60000,
leftovers: TRUE,
copies: 1
];
VersatecTemplate: ImagerPD.PDFileDescriptionRep ← [
fileName: NIL,
deviceCode: mig,
sResolution: 200,
fResolution: 200,
imageSSize: 20000,
imageFSize: 8000,
nColors: 1,
bandSSize: 64,
maxLoadWords: 60000,
leftovers: FALSE,
copies: 1
];
captions: RECORD [
font: Imager.FONT,
nwidth: REAL,
height: REAL
];
left: REAL ← .5*72;
top: REAL ← .75*72;
right: REAL ← .5*72;
bottom: REAL ← .75*72;
pageH: REAL ← 11*72;
pageW: REAL ← 8.5*72;
Init: PROC = {
box: Font.Box;
captions.font ← Font.CreateScaled["Xerox/PressFonts/Helvetica/MRR", 8];
box ← Font.FormattingBox[captions.font,'0];
captions.nwidth ← box.xmax-box.xmin;
captions.height ← box.ymax-box.ymin;
};
Init[];
END.