IPRasterFontSampleImpl.mesa
Copyright (C) 1984, Xerox Corporation. All rights reserved.
Michael Plass, December 19, 1984 10:47:26 am PST
DIRECTORY Basics, AIS, FS, ImagerPixelMaps, IO, IPMaster, RasterFontWriter, Real, Rope, PDFileWriter;
IPRasterFontSampleImpl: CEDAR PROGRAM
IMPORTS Basics, AIS, FS, ImagerPixelMaps, IO, IPMaster, RasterFontWriter, Real, Rope, PDFileWriter
~ BEGIN OPEN IPMaster;
ROPE: TYPE ~ Rope.ROPE;
InternalFont: TYPE ~ RasterFontWriter.InternalFont;
PixelMap: TYPE ~ ImagerPixelMaps.PixelMap;
SetUpTransformation: PROC [stream: STREAM] ~ {
PutRational[stream, 254, 3000000]; -- Want to talk in 300 units per inch
PutOp[stream, scale];
PutOp[stream, concatt];
};
DoUnderTranslate: PROC [stream: STREAM, x, y: INT, proc: PROC] ~ {
PutOp[stream, dosavesimplebody];
PutOp[stream, beginBody];
PutInt[stream, x];
PutInt[stream, y];
PutOp[stream, translate];
PutOp[stream, concatt];
proc[];
PutOp[stream, endBody];
};
Open: PROC [name: ROPE] RETURNS [STREAM] ~ {
stream: STREAM ~ FS.StreamOpen[name, $create];
IO.PutRope[stream, "Interpress/Xerox/2.1 "];
PutOp[stream, beginBlock];
PutOp[stream, beginBody];
PutOp[stream, endBody];
PutOp[stream, beginBody];
SetUpTransformation[stream];
RETURN[stream];
};
NewPage: PROC [stream: STREAM] ~ {
PutOp[stream, endBody];
PutOp[stream, beginBody];
SetUpTransformation[stream];
};
PutRectangle: PROC [stream: STREAM, x, y, w, h: INT] ~ {
PutInt[stream, x];
PutInt[stream, y];
PutInt[stream, w];
PutInt[stream, h];
PutOp[stream, maskrectangle];
};
PutPixelMap: PROC [stream: STREAM, pixelMap: ImagerPixelMaps.PixelMap] ~ TRUSTED {
w: ImagerPixelMaps.DeviceRectangle ~ pixelMap.Window;
PutInt[stream, w.sSize]; -- xPixels
PutInt[stream, (w.fSize+31)/32*32]; -- yPixels
PutInt[stream, 1]; -- samplesPerPixel
PutInt[stream, 1]; -- maxSampleValue
PutInt[stream, 1]; -- samplesInterleaved
PutInt[stream, -90];
PutOp[stream, rotate];
PutInt[stream, w.sMin]; -- x translation
PutInt[stream, w.fMin]; -- y translation
PutOp[stream, translate];
PutOp[stream, concat]; -- m
PutBits[
stream: stream,
base: pixelMap.refRep.pointer,
wordsPerLine: pixelMap.refRep.rast,
sMin: pixelMap.sMin,
fMin: pixelMap.fMin,
sSize: pixelMap.sSize,
fSize: pixelMap.fSize
]; -- bits, bits, bits
PutOp[stream, makepixelarray];
};
Finish: PROC [stream: STREAM] ~ {
PutOp[stream, endBody];
PutOp[stream, endBlock];
IO.Close[stream];
};
MakeSample: PROC [ipFileName: ROPE] ~ {
stream: STREAM ← Open[ipFileName];
k: NAT ← 1;
leftMargin: INT ← 0;
bottomMargin: INT ← 0;
columnMargin: INT ← 0;
baseline: INT ← 0;
baselineStart: INT ← 0;
inch: INT ← 300;
wPixels: INT ← 85*inch/10;
hPixels: INT ← 11*inch;
linewidth: INT ← Real.RoundLI[lineInches*inch];
IF landscape THEN {
PutInt[stream, wPixels]; PutInt[stream, 0]; PutOp[stream, translate]; PutOp[stream, concatt];
PutInt[stream, 90]; PutOp[stream, rotate]; PutOp[stream, concatt];
};
baseline ← baselineStart ← (IF landscape THEN wPixels ELSE hPixels) - inch;
leftMargin ← inch;
columnMargin ← leftMargin/2;
bottomMargin ← inch;
k ← 1;
FOR p: LIST OF RopePair ← rasterFontFileNames, p.rest UNTIL p = NIL DO
myText: ROPE ← text.Concat[p.first.id];
length: INT ← myText.Length;
start: INT ← 0;
font: RasterFontWriter.InternalFont ← RasterFontWriter.Load[p.first.name];
baselineskip: INT ← Real.RoundLI[(1.0+leading)*font.bitsPerEmQuad];
WHILE start < length DO
lineChars: INT ← FindLineBreak[myText, start, linewidth, font];
sWidth: REAL ← 0;
fWidth: REAL ← 0;
FOR i: INT IN [start..start+lineChars) DO
c: CHAR ← myText.Fetch[i];
charRep: RasterFontWriter.InternalCharRep ← font.charRep[c];
pm: ImagerPixelMaps.PixelMap ~ charRep.pixels.Trim;
y: INT ← baseline-Real.RoundLI[sWidth];
x: INT ← leftMargin+Real.RoundLI[fWidth];
proc: PROC ~ {
PutPixelMap[stream, pm];
PutOp[stream, maskpixel];
};
IF pm.sSize # 0 AND pm.fSize # 0 THEN DoUnderTranslate[stream, x, y, proc];
sWidth ← sWidth + charRep.sWidth;
fWidth ← fWidth + charRep.fWidth;
ENDLOOP;
start ← start + lineChars;
baseline ← baseline - baselineskip;
IF baseline <= bottomMargin THEN {
baseline ← baselineStart;
leftMargin ← leftMargin + linewidth + columnMargin;
};
ENDLOOP;
k ← k + 1;
baseline ← baseline - baselineskip;
ENDLOOP;
Finish[stream];
};
fontPerColumn: BOOLEANTRUE;
lineInches: REAL ← 6.5;
MakeSamplePixels: PROC [action: PROC [pm: ImagerPixelMaps.PixelMap], inch: INT, pageBB: ImagerPixelMaps.DeviceRectangle] ~ {
k: NAT ← 1;
wPixels: INT ← pageBB.fSize;
hPixels: INT ← pageBB.sSize;
linewidth: INT ← Real.RoundLI[lineInches*inch];
leftMargin: INT ← 0;
bottomMargin: INT ← 0;
columnMargin: INT ← 0;
baseline: INT ← 0;
baselineStart: INT ← 0;
top: INT ~ (IF landscape THEN wPixels ELSE hPixels);
baseline ← baselineStart ← top - inch;
leftMargin ← inch;
columnMargin ← leftMargin/2;
bottomMargin ← inch;
k ← 1;
FOR p: LIST OF RopePair ← rasterFontFileNames, p.rest UNTIL p = NIL DO
myText: ROPE ← text.Concat[p.first.id];
length: INT ← myText.Length;
start: INT ← 0;
font: RasterFontWriter.InternalFont ← RasterFontWriter.Load[p.first.name];
baselineskip: INT ← Real.RoundLI[(1.0+leading)*font.bitsPerEmQuad];
WHILE start < length DO
lineChars: INT ← FindLineBreak[myText, start, linewidth, font];
sWidth: REAL ← 0;
fWidth: REAL ← 0;
FOR i: INT IN [start..start+lineChars) DO
c: CHAR ← myText.Fetch[i];
charRep: RasterFontWriter.InternalCharRep ← font.charRep[c];
pm: ImagerPixelMaps.PixelMap ~ charRep.pixels.Trim;
y: INT ← baseline-Real.RoundLI[sWidth];
x: INT ← leftMargin+Real.RoundLI[fWidth];
IF c # ' AND c # '\n AND pm.sSize # 0 AND pm.fSize # 0 THEN action[pm.ShiftMap[top-y, x]];
sWidth ← sWidth + charRep.sWidth;
fWidth ← fWidth + charRep.fWidth;
ENDLOOP;
start ← start + lineChars;
baseline ← baseline - baselineskip;
IF baseline <= bottomMargin THEN {
baseline ← baselineStart;
leftMargin ← leftMargin + linewidth + columnMargin;
};
ENDLOOP;
k ← k + 1;
baseline ← baseline - baselineskip;
IF fontPerColumn THEN {
baseline ← baselineStart;
leftMargin ← leftMargin + linewidth + columnMargin;
};
ENDLOOP;
};
StorePixelMap: PROC [aisFileName: ROPE, source: ImagerPixelMaps.PixelMap, bitmap: BOOLEANTRUE, comment: ROPE ← NIL] ~ TRUSTED {
output: AIS.FRef ← AIS.CreateFile[name: aisFileName, raster: NEW[AIS.RasterPart ← [
scanCount: source.sSize,
scanLength: source.fSize,
scanMode: rd,
bitsPerPixel: IF source.refRep.lgBitsPerPixel = 0 AND bitmap THEN 0 ELSE Basics.BITSHIFT[1, source.refRep.lgBitsPerPixel],
linesPerBlock: -1,
paddingPerBlock: 65535
]]];
outputWindow: AIS.WRef ← AIS.OpenWindow[output];
lineMap: ImagerPixelMaps.PixelMap ← ImagerPixelMaps.Create[source.refRep.lgBitsPerPixel, [source.sOrigin+source.sMin, source.fOrigin+source.fMin, 1, source.fSize]];
lineBufferDesc: AIS.Buffer ← [length: lineMap.refRep.words, addr: lineMap.refRep.pointer];
AIS.WriteComment[output, comment];
FOR i: NAT IN [0..source.sSize) DO
lineMap.Clear;
lineMap.Transfer[source];
lineMap.sOrigin ← lineMap.sOrigin + 1;
AIS.UnsafeWriteLine[outputWindow, lineBufferDesc, i];
ENDLOOP;
AIS.CloseFile[output];
};
MultipleOf32: PROC [nat: NAT] RETURNS [NAT] ~ {
RETURN [Basics.BITAND[nat + 31, CARDINAL.LAST-31]]
};
FindBB: PROC [inch: INT, pageBB: ImagerPixelMaps.DeviceRectangle] RETURNS [ImagerPixelMaps.DeviceRectangle] ~ {
sMin: INTINT.LAST;
fMin: INTINT.LAST;
sMax: INTINT.FIRST;
fMax: INTINT.FIRST;
action: PROC [pm: ImagerPixelMaps.PixelMap] ~ {
sMin ← MIN[sMin, pm.sOrigin+pm.sMin];
sMax ← MAX[sMax, pm.sOrigin+pm.sMin+pm.sSize];
fMin ← MIN[fMin, pm.fOrigin+pm.fMin];
fMax ← MAX[fMax, pm.fOrigin+pm.fMin+pm.fSize];
};
MakeSamplePixels[action, inch, pageBB];
IF sMin > sMax THEN RETURN [[0, 0, 0, 0]]
ELSE RETURN [[sMin, fMin, MultipleOf32[sMax-sMin], MultipleOf32[fMax-fMin]]]
};
MakeSampleAIS: PROC [aisFileName: ROPE, comment: ROPE, inch: INT, longEdgeFeed: BOOLEANTRUE] ~ {
pageBB: ImagerPixelMaps.DeviceRectangle ~ IF longEdgeFeed THEN [0, 0, 85*inch/10, 11*inch] ELSE [0, 0, 11*inch, 85*inch/10];
w: ImagerPixelMaps.DeviceRectangle ~ FindBB[inch, pageBB];
pixelMap: ImagerPixelMaps.PixelMap ← ImagerPixelMaps.Create[0, w];
action: PROC [pm: ImagerPixelMaps.PixelMap] ~ {pixelMap.Transfer[pm, [or, null]]};
pixelMap.Clear;
MakeSamplePixels[action, inch, pageBB];
StorePixelMap[aisFileName, pixelMap, TRUE, comment];
};
tileBits: ARRAY [0..16) OF PACKED ARRAY [0..16) OF {O,X} ← [
[X,X,X,X,X,X,X,X,O,O,O,O,O,O,O,O],
[X,X,X,X,X,X,X,X,O,O,O,O,O,O,O,O],
[X,X,X,X,X,X,X,X,O,O,O,O,O,O,O,O],
[X,X,X,X,X,X,X,X,O,O,O,O,O,O,O,O],
[X,X,X,X,X,X,X,X,O,O,O,O,O,O,O,O],
[X,X,X,X,X,X,X,X,O,O,O,O,O,O,O,O],
[X,X,X,X,X,X,X,X,O,O,O,O,O,O,O,O],
[X,X,X,X,X,X,X,X,O,O,O,O,O,O,O,O],
[O,O,O,O,O,O,O,O,X,X,X,X,X,X,X,X],
[O,O,O,O,O,O,O,O,X,X,X,X,X,X,X,X],
[O,O,O,O,O,O,O,O,X,X,X,X,X,X,X,X],
[O,O,O,O,O,O,O,O,X,X,X,X,X,X,X,X],
[O,O,O,O,O,O,O,O,X,X,X,X,X,X,X,X],
[O,O,O,O,O,O,O,O,X,X,X,X,X,X,X,X],
[O,O,O,O,O,O,O,O,X,X,X,X,X,X,X,X],
[O,O,O,O,O,O,O,O,X,X,X,X,X,X,X,X]
];
MakeSamplePD: PROC [pdFileName: ROPE, res: INT ← 300, longEdgeFeed: BOOLEANTRUE] ~ {
pageBB: ImagerPixelMaps.DeviceRectangle ~ IF longEdgeFeed THEN [0, 0, 85*res/10, 11*res] ELSE [0, 0, 11*res, 85*res/10];
pd: PDFileWriter.PDState ← PDFileWriter.Create[fileName: pdFileName, deviceCode: hornet, sResolution: res, fResolution: res, imageSSize: pageBB.sSize, imageFSize: pageBB.fSize];
scratch: REF ImagerPixelMaps.PixelMapRep ← NIL;
action: PROC [pm: ImagerPixelMaps.PixelMap] ~ {
w: ImagerPixelMaps.DeviceRectangle ← (pm ← pm.Clip[pageBB].Copy[scratch]).Window;
p: LONG POINTER ← pm.refRep.pointer;
rast: LONG CARDINAL ← pm.refRep.rast;
deliverProc: PROC [line: PROC [LONG POINTER]] ~ TRUSTED {
THROUGH [0..w.sSize) DO
line[p];
p ← p + rast;
ENDLOOP;
};
IF w.sSize = 0 THEN RETURN;
pd.MaskSamples[w.sMin, w.fMin, w.sSize, w.fSize, deliverProc];
scratch ← pm.refRep;
};
barwidth: NAT ← res/2;
tileReference: LONG CARDINAL;
TRUSTED {tileReference ← pd.LoadContiguousColorTile[0, 0, 0, 16, 16, @tileBits]};
MakeSamplePixels[action, res, pageBB];
pd.SetColorTile[black, tileReference];
pd.MaskRectangle[0, 0, barwidth, pageBB.fSize];
pd.MaskRectangle[0, 0, pageBB.sSize, barwidth];
pd.MaskRectangle[0, pageBB.fSize-barwidth, pageBB.sSize, barwidth];
pd.MaskRectangle[pageBB.sSize-barwidth, 0, barwidth, pageBB.fSize];
pd.EndPage;
pd.Close;
};
FindLineBreak: PROC [myText: ROPE, start: INT, width: REAL, font: RasterFontWriter.InternalFont] RETURNS [charCount: INT ← 0] ~ {
FOR i: INT IN [0..myText.Length-start) DO
c: CHAR ← myText.Fetch[start+i];
charRep: RasterFontWriter.InternalCharRep ← font.charRep[c];
width ← width - charRep.fWidth;
IF width <= 0 THEN {
IF charCount = 0 THEN charCount ← MAX[i+1, 1];
WHILE start+charCount < myText.Length AND myText.Fetch[start+charCount] = ' DO
charCount ← charCount + 1;
ENDLOOP;
RETURN;
};
IF c = '\n THEN {
charCount ← i+1;
RETURN;
};
IF c = ' THEN charCount ← i+1;
ENDLOOP;
charCount ← myText.Length-start;
};
AddFont: PROC [rasterFontFileName: ROPE, id: ROPENIL] ~ {
IF id = NIL THEN id ← Rope.Concat["\n", rasterFontFileName];
rasterFontFileNames ← CONS[[rasterFontFileName, id], rasterFontFileNames];
};
RopePair: TYPE ~ RECORD [name, id: ROPE];
rasterFontFileNames: LIST OF RopePair;
leading: REAL ← 0.2; -- in ems
landscape: BOOLEANFALSE;
zapf: ROPE ← "I think that there is no question that we have to create a new concept in the typographic field. This indicates the common trend which is part of our present day and future living. There is a permanent movement in so many fields towards the future. We too often look backwards in our love for the oldtimers in types; we are sometimes still captured by false romanticism, and we should spend part of our activities for new developments. -- Hermann Zapf ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 !@#$%~&*()-+=|\\{}[]:;\"\'<>,.?/";
grimm: ROPE ← "In olden times when wishing still helped one, there lived a king whose daughters were all beautiful, but the youngest was so beautiful that the sun itself, which has seen so much, was astonished whenever it shone in her face. Close by the king's castle lay a great dark forest, and under an old lime-tree in the forest was a well, and when the day was very warm, the king's child went out into the forest and sat down by the side of the cool fountain, and when she was bored she took a golden ball, and threw it up on high and caught it, and this ball was her favorite plaything.";
text: ROPE ← grimm;
END.