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
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
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: BOOLEAN ← TRUE;
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:
BOOLEAN ←
TRUE, 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: INT ← INT.LAST;
fMin: INT ← INT.LAST;
sMax: INT ← INT.FIRST;
fMax: INT ← INT.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:
BOOLEAN ←
TRUE] ~ {
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:
BOOLEAN ←
TRUE] ~ {
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:
ROPE ←
NIL] ~ {
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:
BOOLEAN ←
FALSE;
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.";
END.