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: BOOLEAN ← TRUE;
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: PROC ← IF 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.