DIRECTORY
Imager,
ImagerBasic USING [PixelArray],
ImagerTransform USING [InverseTransform, Contents],
ImagerPD USING[PDFileDescription, PDFileDescriptionRep, Hornet],
PDFileFormat,
Real USING [Fix],
SampledColors USING[bitmap, DrawImage],
UFFileManager USING[KeyOf],
UFPressFontReader USING[Size, Range, Family, Face, Resolution, GetCharInfo, GetCharRaster, CharInfo, NumberOfFontsInFile],
Font USING [Key, CreateScaled, FONT, Box, FormattingBox],
Rope USING [ROPE, Cat, Substr],
Convert USING [RopeFromInt],
FS USING [ExpandName, ComponentPositions],
IO USING [time, rope, real, int, PutFR],
BasicTime,
PrintAC;
PrintACImpl:
CEDAR PROGRAM
IMPORTS Imager, SampledColors, Rope, ImagerTransform, Real, UFFileManager, UFPressFontReader, Font, Convert, ImagerPD, FS, IO, BasicTime
EXPORTS = BEGIN OPEN PrintAC;
ROPE: TYPE = Rope.ROPE;
for debugging
doChars: BOOLEAN ← TRUE;
doPages: BOOLEAN ← FALSE;
PrintACChars:
PUBLIC PROC[name:
ROPE, device: DeviceType, scale:
REAL, chars:
ROPE]
RETURNS [pd:
ROPE];
Prints only the chars in the rope
PrintACCodes:
PUBLIC PROC[name:
ROPE, device: DeviceType, scale:
REAL, codes0, codes1, codes2, codes3, codes4: Subrange ← [0,0]]
RETURNS [pd:
ROPE];
Prints only the chars in the subranges
PrintACFile:
PUBLIC PROC[name:
ROPE, device: DeviceType, scale:
REAL]
RETURNS [
ROPE] = {
Prints all the characters in the file
acFont: InternalFont;
base, wdir, label: ROPE;
maxH, maxW, gl, gt: REAL ← 0;
areaW, areaH, boxW, boxH: REAL;
nw, nh: INT;
bc, nchars: NAT;
ctx: Imager.Context;
[base, wdir] ← GetName[name];
acFont ← LoadAC[Rope.Cat[wdir,base,".ac"]];
ctx ← OpenPD[Rope.Cat[wdir,base,".pd"], device];
maxW ← acFont.maxW*scale; --max size a function of scale
maxH ← (acFont.ascent+acFont.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];
label ← IO.PutFR["%g.ac, scale=%g, time= %g", IO.rope[base], IO.real[scale], IO.time[]];
bc ← VAL[acFont.bc];
nchars ← ORD[acFont.ec-VAL[bc]];
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, acFont, 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[acFont.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, acFont, VAL[bc], gl, gt, nw, nh, boxW, boxH, scale];
[] ← Imager.SpecialOp[ctx, $Close, NIL];
RETURN[Rope.Cat[wdir,base,".pd"]];
};
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, acFont: InternalFont, 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;
DoRow:
PROC = {
FOR i:
INT
IN [0..nw)
DO
IF acFont.charRep[char].pixels#
NIL
THEN {
dx: REAL ← (bitsW-acFont.charRep[char].width)/2.0; --center it
Imager.TranslateT[ctx, dx, 0];
SampledColors.DrawImage[ctx,acFont.charRep[char].pixels,SampledColors.bitmap];
Imager.TranslateT[ctx,bitsW-dx,0];
}
ELSE Imager.TranslateT[ctx, bitsW, 0];
char ← char+1;
IF char > acFont.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, -acFont.ascent]; --drop down by the maximum ascent
FOR i:
INT
IN [0..nh)
DO
Imager.DoSaveAll[ctx, DoRow];
IF char > acFont.ec THEN EXIT;
Imager.TranslateT[ctx, 0, -bitsH];
ENDLOOP;
};
OpenPD:
PROC[name:
ROPE, device: DeviceType]
RETURNS [ctx: Imager.Context] = {
pdDescr: ImagerPD.PDFileDescription ←
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: 8, showRadix: TRUE]]};
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]
};
FontNotFound: SIGNAL = CODE;
Copied out of RasterFontWriterImpl. Changed PixelMap to PixelArray
InternalFont: TYPE ~ REF InternalFontRep;
InternalFontRep:
TYPE ~
RECORD [
family: Rope.ROPE ← NIL,
face: [0..255] ← 0,
descent, ascent, maxW: REAL ← 0,
bc, ec: CHAR,
charRep: ARRAY CHAR OF InternalCharRep
];
InternalCharRep:
TYPE ~
RECORD [
width: REAL,
pixels: ImagerBasic.PixelArray
];
LoadAC:
PROC [fileName: Rope.
ROPE]
RETURNS [font: InternalFont] ~
TRUSTED {
fileKey: Font.Key ← UFFileManager.KeyOf[fileName];
sizeInMeters, bitsPerEmQuad: REAL;
IF UFPressFontReader.NumberOfFontsInFile[fileKey] = 0 THEN SIGNAL FontNotFound;
sizeInMeters ← UFPressFontReader.Size[[fileKey, 0]];
font ← NEW [InternalFontRep];
[font.bc, font.ec] ← UFPressFontReader.Range[[fileKey, 0]];
font.family ← UFPressFontReader.Family[[fileKey, 0]];
font.face ← UFPressFontReader.Face[[fileKey, 0]];
bitsPerEmQuad ← sizeInMeters*UFPressFontReader.Resolution[[fileKey, 0]].xRes/0.0254;
FOR char:
CHAR
IN [font.bc..font.ec]
DO
info: UFPressFontReader.CharInfo ← UFPressFontReader.GetCharInfo[[fileKey, 0], char];
pixelArray: ImagerBasic.PixelArray ← UFPressFontReader.GetCharRaster[[fileKey, 0], char];
font.charRep[char] ← [
width: (info.maxX-info.minX)*bitsPerEmQuad,
pixels: pixelArray
];
IF font.charRep[char].width > font.maxW THEN font.maxW ← font.charRep[char].width;
IF info.maxY > font.ascent THEN font.ascent ← info.maxY;
IF ABS[info.minY] > font.descent THEN font.descent ← ABS[info.minY];
ENDLOOP;
font.ascent ← font.ascent*bitsPerEmQuad;
font.descent ← font.descent*bitsPerEmQuad;
};
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", 10];
box ← Font.FormattingBox[captions.font,'0];
captions.nwidth ← box.xmax-box.xmin;
captions.height ← box.ymax-box.ymin;
};
END.