PressOverlayImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Michael Plass, July 29, 1985 10:05:37 am PDT
Last Edited by: Beach, May 1, 1985 4:23:47 pm PDT
DIRECTORY
Commander USING [CommandProc, Handle, Register],
FS USING [Error, FileInfo],
IO USING [CharClass, EndOfStream, GetIndex, GetTokenRope, int, PutChar, PutFR, PutRope, RIS, SetIndex, STREAM, UnsafeGetBlock],
PressOverlay USING [],
PressPrinter USING [IsAPressFile],
PressReader USING [AlternativeProc, ClosePressFile, ColorProc, DocumentDirectory, Dots, DotsFollowProc, DrawCurveProc, DrawToProc, EntityProc, FontDirectoryEntry, FontDirectoryProc, FontEntryProc, FontProc, GetCommands, GetDocumentDirectory, GetDots, GetFonts, GetObject, GetPage, GetParts, Handle, MoveToProc, OpenPressFile, PageProc, PositionProc, SetCodingProc, SetModeProc, SetSizeProc, SetWindowProc, ShowCharactersProc, ShowDotsProc, ShowObjectProc, ShowRectangleProc, SpaceProc, SpacingProc],
Real USING [RoundLI],
Rope USING [Concat, Equal, Find, IsEmpty, Length, ROPE, Substr],
SirPress USING [BeginScannedRectangle, ClosePress, EndOutline, EndScannedRectangle, NewPressHandle, PressHandle, PutCubic, PutDrawTo, PutMoveTo, PutRectangle, PutText, PutTextHere, ResetSpace, SetBrightness, SetColor, SetFont, SetHue, SetSaturation, SetSpace, StartOutline, UnsafeShowLine, WritePage];
PressOverlayImpl: CEDAR PROGRAM
IMPORTS Commander, FS, IO, PressReader, Real, Rope, SirPress, PressPrinter
EXPORTS PressOverlay
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
bytesPerPage: NAT ~ 512; -- as per press file format.
micasPerPoint: REAL = 2540.0/72.0;
pointsPerMica: REAL = 72.0/2540.0;
CopyPressPage: PUBLIC PROC [pressHandle: SirPress.PressHandle, pressFile: PressReader.Handle, pageNumber: INT, fontTable: REF ARRAY [0..6*16) OF PressReader.FontDirectoryEntry] RETURNS [ok: BOOLEANTRUE] = {
PageProc: PressReader.PageProc = {
EntityProc: PressReader.EntityProc = { -- Xe, Ye, fontSet
xe: INT ← entityTrailer.Xe;
ye: INT ← entityTrailer.Ye;
x: INT ← xe;
y: INT ← ye;
currentFont: PressReader.FontDirectoryEntry; -- will be established by setFont
currentSpaceX, currentSpaceY: INT; -- will be established by setFont
hue: REAL ← 0.0;
saturation: REAL ← 1.0;
brightness: REAL ← 0.0;
skipAlternative, inAlternative: BOOLFALSE;
reposition: BOOLEANFALSE;
showCharactersProc: PressReader.ShowCharactersProc = {
IF skipAlternative THEN RETURN;
IF reposition THEN {pressHandle.PutText[text, x, y]; reposition ← FALSE}
ELSE pressHandle.PutTextHere[text];
}; -- showCharactersProc
fontProc: PressReader.FontProc = {
IF skipAlternative THEN RETURN;
currentFont ← fontTable[entityTrailer.fontSet*16+font];
IF currentFont.family.Length # 0 THEN
pressHandle.SetFont[currentFont.family, currentFont.size, currentFont.face.encoding, currentFont.rotation];
};
positionProc: PressReader.PositionProc = {
IF skipAlternative THEN RETURN;
IF opCode = setX THEN x ← xe + value
ELSE y ← ye + value;
reposition ← TRUE;
};
spacingProc: PressReader.SpacingProc = {
IF skipAlternative THEN RETURN;
SELECT opCode FROM
setSpaceX, setSpaceXShort => currentSpaceX ← value;
setSpaceY, setSpaceYShort => currentSpaceY ← value;
resetSpace => {
currentSpaceX ← 200;
currentSpaceY ← 0;
};
ENDCASE => ERROR;
IF opCode = resetSpace THEN pressHandle.ResetSpace ELSE pressHandle.SetSpace[currentSpaceX, currentSpaceY];
};
spaceProc: PressReader.SpaceProc = {
showCharactersProc[showCharacterImmediate, 1, " "];
};
colorProc: PressReader.ColorProc = {
IF skipAlternative THEN RETURN;
SELECT opCode FROM
setHue => pressHandle.SetHue[value];
setSaturation => pressHandle.SetSaturation[value];
setBrightness => pressHandle.SetBrightness[value];
ENDCASE => ERROR;
};
showRectangleProc: PressReader.ShowRectangleProc = {
IF skipAlternative THEN RETURN;
pressHandle.PutRectangle[x, y, width, height];
};
alternativeProc: PressReader.AlternativeProc = {
IF (types = 0) AND (elBytes = 0) AND (dlBytes = 0) THEN
inAlternative ← skipAlternative ← FALSE
ELSE IF inAlternative THEN skipAlternative ← TRUE
ELSE inAlternative ← TRUE;
};
showObjectProc: PressReader.ShowObjectProc = {
moveToProc: PressReader.MoveToProc = {
pressHandle.PutMoveTo[x: x+xe, y: y+ye]};
drawToProc: PressReader.DrawToProc = {
pressHandle.PutDrawTo[x: x+xe, y: y+ye]};
drawCurveProc: PressReader.DrawCurveProc = {
pressHandle.PutCubic[cX, cY, bX, bY, aX, aY];
};
IF skipAlternative THEN RETURN;
pressHandle.StartOutline;
pressFile.GetObject[moveToProc, drawToProc, drawCurveProc];
pressHandle.EndOutline;
}; -- showObjectProc
showDotsProc: PressReader.ShowDotsProc = {
codingType, dotsPerLine, scanLines, passDots, displayDots, passLines, displayLines: INT ← 0;
scanMode: CARDINAL ← 0;
windowWidth, windowHeight: INT ← 0;
dotInfo: PressReader.Dots;
setCodingProc: PressReader.SetCodingProc = {
codingType ← code;
windowWidth ← dotsPerLine ← displayDots ← dots;
windowHeight ← scanLines ← displayLines ← lines;
};
setModeProc: PressReader.SetModeProc = {scanMode ← mode};
setWindowProc: PressReader.SetWindowProc = {
passDots ← pd;
displayDots ← dd;
passLines ← pl;
displayLines ← dl;
};
setSizeProc: PressReader.SetSizeProc = {
windowWidth ← width;
windowHeight ← height;
};
dotsFollowProc: PressReader.DotsFollowProc = {
dotInfo ← dots;
};
ScratchRec: TYPE ~ RECORD [SEQUENCE length: NAT OF WORD];
scratch: REF ScratchRec;
bytesPerLine: INT ← 0;
IF skipAlternative THEN RETURN;
pressFile.GetDots[setCoding: setCodingProc, setMode: setModeProc,
setWindow: setWindowProc, setSize: setSizeProc, dotsFollow: dotsFollowProc];
scratch ← NEW[ScratchRec[(dotsPerLine+3)/2]];
pressHandle.BeginScannedRectangle[
x: x, y: y,
dotsPerLine: dotsPerLine,
numberOfLines: scanLines,
width: windowWidth,
height: windowHeight,
nextLineDirection: LOOPHOLE[scanMode MOD 4],
nextDotDirection: LOOPHOLE[scanMode / 4],
coding: SELECT codingType FROM
0 => bitMap,
1 => bitSampled,
2 => bitBitSampled,
4 => nybbleSampled,
8 => byteSampled,
ENDCASE => ERROR
];
bytesPerLine ← (MAX[codingType, 1] * dotsPerLine + 7)/8;
scratch[bytesPerLine/2] ← 0; -- make sure array is big enough
dotInfo.file.SetIndex[INT[dotInfo.pageNumber]*bytesPerPage+dotInfo.byteOffset];
FOR i: INT IN [0..scanLines) DO
TRUSTED {[] ← dotInfo.file.UnsafeGetBlock[[base: (LOOPHOLE[@scratch[0]]), startIndex: 0, count: bytesPerLine]]};
TRUSTED {pressHandle.UnsafeShowLine[@scratch[0]]};
ENDLOOP;
pressHandle.EndScannedRectangle;
}; -- showDotsProc
fontProc[0];
pressHandle.SetColor[0, 0, 0];
pressFile.GetCommands[
showCharactersProc: showCharactersProc,
fontProc: fontProc,
positionProc: positionProc,
spacingProc: spacingProc,
spaceProc: spaceProc,
colorProc: colorProc,
showRectangleProc: showRectangleProc,
alternativeProc: alternativeProc,
showObjectProc: showObjectProc,
showDotsProc: showDotsProc
];
}; -- EntityProc
pressFile.GetPage[EntityProc];
}; -- PageProc
SkipFonts: PressReader.FontDirectoryProc = {
ok ← FALSE;
};
pressFile.GetParts[pageNumber, PageProc, SkipFonts];
};
Overlay: PUBLIC PROC [outputName, inputName1, inputName2: ROPE] ~ {
pressFile1: PressReader.Handle ← PressReader.OpenPressFile[inputName1];
documentDirectory1: PressReader.DocumentDirectory ← pressFile1.GetDocumentDirectory;
pressFile2: PressReader.Handle ← PressReader.OpenPressFile[inputName2];
documentDirectory2: PressReader.DocumentDirectory ← pressFile2.GetDocumentDirectory;
pageNumber1: INT ← 1;
pageNumber2: INT ← 1;
fontTable: ARRAY [1..2] OF REF ARRAY [0..6*16) OF PressReader.FontDirectoryEntry ← [NEW[ARRAY [0..6*16) OF PressReader.FontDirectoryEntry], NEW[ARRAY [0..6*16) OF PressReader.FontDirectoryEntry]];
FontInitProc1: PressReader.FontEntryProc = { -- build a list of needed fonts
fontTable[1][fontDirectoryEntry.fontSet*16 + fontDirectoryEntry.font] ← fontDirectoryEntry;
}; -- FontInitProc
FontInitProc2: PressReader.FontEntryProc = { -- build a list of needed fonts
fontTable[2][fontDirectoryEntry.fontSet*16 + fontDirectoryEntry.font] ← fontDirectoryEntry;
}; -- FontInitProc
pressHandle: SirPress.PressHandle ← SirPress.NewPressHandle[outputName];
pressFile1.GetFonts[FontInitProc1];
pressFile2.GetFonts[FontInitProc2];
WHILE CopyPressPage[pressHandle, pressFile1, pageNumber1, fontTable[1]] DO
UNTIL CopyPressPage[pressHandle, pressFile2, pageNumber2, fontTable[2]] DO
pageNumber2 ← 1;
ENDLOOP;
pageNumber1 ← pageNumber1 + 1;
pageNumber2 ← pageNumber2 + 1;
pressHandle.WritePage;
ENDLOOP;
pressFile1.ClosePressFile[];
pressFile2.ClosePressFile[];
pressHandle.ClosePress;
};
Break: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← THEN RETURN [break];
IF char = ' OR char = '  OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
FindFullName: PROC [inputName: ROPE] RETURNS [ROPE] ~ {
fullFName: ROPENIL;
fullFName ← FS.FileInfo[inputName ! FS.Error => CONTINUE].fullFName;
IF fullFName = NIL OR NOT PressPrinter.IsAPressFile[fullFName] THEN {
IF inputName.Find[".press", 0, FALSE] = -1 THEN {
inputName ← inputName.Concat[".press"];
};
fullFName ← FS.FileInfo[inputName].fullFName;
};
RETURN [fullFName]
};
PressOverlayCommand: Commander.CommandProc ~ {
stream: IO.STREAMIO.RIS[cmd.commandLine];
GetToken: PROC RETURNS [rope: ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token;
};
outputName: ROPE ← GetToken[];
gets: ROPE ← GetToken[];
inputName1: ROPE ← GetToken[];
inputName2: ROPE ← GetToken[];
IF NOT gets.Equal["←"] OR inputName2 = NIL THEN {cmd.out.PutRope["Specify output ← input1 input2, please"]; RETURN};
IF outputName.Find[".press", 0, FALSE] = -1 THEN {
outputName ← outputName.Concat[".press"];
};
inputName1 ← FindFullName[inputName1 ! FS.Error => {
IF error.group = user THEN {cmd.out.PutRope[error.explanation]; cmd.out.PutChar['\n]; GOTO Quit} ELSE REJECT
}];
inputName2 ← FindFullName[inputName2 ! FS.Error => {
IF error.group = user THEN {cmd.out.PutRope[error.explanation]; cmd.out.PutChar['\n]; GOTO Quit} ELSE REJECT
}];
Overlay[outputName, inputName1, inputName2];
cmd.out.PutRope[outputName];
cmd.out.PutRope[" written.\n"];
IF GetToken[].Length # 0 THEN {cmd.out.PutRope["Ignored: "]; cmd.out.PutRope[cmd.commandLine.Substr[stream.GetIndex]]; cmd.out.PutChar['\n]};
EXITS Quit => NULL
};
FindBBoxPage: PUBLIC PROC [--pressHandle: SirPress.PressHandle,-- pressFile: PressReader.Handle, pageNumber: INT, fontTable: REF ARRAY [0..6*16) OF PressReader.FontDirectoryEntry] RETURNS [leftMargin, topMargin, rightMargin, bottomMargin: INT, ok: BOOLEAN] = {
leftMax: INTLAST[INT];
topMax: INTFIRST[INT];
rightMax: INTFIRST[INT];
bottomMax: INTLAST[INT];
SetBBox: PROC [x, y, width, height: INT] ~ {
leftMax ← MIN[leftMax, x];
topMax ← MAX[topMax, y-height];
rightMax ← MAX[rightMax, x+width];
bottomMax ← MIN[bottomMax, y];
};
PageProc: PressReader.PageProc = {
EntityProc: PressReader.EntityProc = { -- Xe, Ye, fontSet
xe: INT ← entityTrailer.Xe;
ye: INT ← entityTrailer.Ye;
x: INT ← xe;
y: INT ← ye;
currentFont: PressReader.FontDirectoryEntry; -- will be established by setFont
currentSpaceX, currentSpaceY: INT; -- will be established by setFont
hue: REAL ← 0.0;
saturation: REAL ← 1.0;
brightness: REAL ← 0.0;
skipAlternative, inAlternative: BOOLFALSE;
reposition: BOOLEANFALSE;
showCharactersProc: PressReader.ShowCharactersProc = {
widthOfText: INT ← 1;
heightOfText: INT ← 1;
IF skipAlternative THEN RETURN;
IF reposition THEN {
SetBBox[x, y, widthOfText, heightOfText];
pressHandle.PutText[text, x, y];
reposition ← FALSE}
ELSE {
SetBBox[x, y, widthOfText, heightOfText];
pressHandle.PutTextHere[text];
};
}; -- showCharactersProc
fontProc: PressReader.FontProc = {
IF skipAlternative THEN RETURN;
currentFont ← fontTable[entityTrailer.fontSet*16+font];
IF currentFont.family.Length # 0 THEN
pressHandle.SetFont[currentFont.family, currentFont.size, currentFont.face.encoding, currentFont.rotation];
};
positionProc: PressReader.PositionProc = {
IF skipAlternative THEN RETURN;
IF opCode = setX THEN x ← xe + value
ELSE y ← ye + value;
reposition ← TRUE;
};
spacingProc: PressReader.SpacingProc = {
IF skipAlternative THEN RETURN;
SELECT opCode FROM
setSpaceX, setSpaceXShort => currentSpaceX ← value;
setSpaceY, setSpaceYShort => currentSpaceY ← value;
resetSpace => {
currentSpaceX ← 200;
currentSpaceY ← 0;
};
ENDCASE => ERROR;
IF opCode = resetSpace THEN pressHandle.ResetSpace ELSE pressHandle.SetSpace[currentSpaceX, currentSpaceY];
};
spaceProc: PressReader.SpaceProc = {
showCharactersProc[showCharacterImmediate, 1, " "];
};
colorProc: PressReader.ColorProc = {
IF skipAlternative THEN RETURN;
SELECT opCode FROM
setHue => pressHandle.SetHue[value];
setSaturation => pressHandle.SetSaturation[value];
setBrightness => pressHandle.SetBrightness[value];
ENDCASE => ERROR;
};
showRectangleProc: PressReader.ShowRectangleProc = {
IF skipAlternative THEN RETURN;
SetBBox[x, y, width, height];
pressHandle.PutRectangle[x, y, width, height];
};
alternativeProc: PressReader.AlternativeProc = {
IF (types = 0) AND (elBytes = 0) AND (dlBytes = 0) THEN
inAlternative ← skipAlternative ← FALSE
ELSE IF inAlternative THEN skipAlternative ← TRUE
ELSE inAlternative ← TRUE;
};
showObjectProc: PressReader.ShowObjectProc = {
curveX, curveY: INT;
moveToProc: PressReader.MoveToProc = {
curveX ← x+xe;
curveY ← y+ye;
SetBBox[curveX, curveY, 0, 0];
pressHandle.PutMoveTo[x: x+xe, y: y+ye];
};
drawToProc: PressReader.DrawToProc = {
curveX ← x+xe;
curveY ← y+ye;
SetBBox[curveX, curveY, 0, 0];
pressHandle.PutDrawTo[x: x+xe, y: y+ye]
};
drawCurveProc: PressReader.DrawCurveProc = {
minX: INT ~ Real.RoundLI[MIN[cX, bX, aX]];
minY: INT ~ Real.RoundLI[MIN[cY, bY, aY]];
maxX: INT ~ Real.RoundLI[MAX[cX, bX, aX]];
maxY: INT ~ Real.RoundLI[MAX[cY, bY, aY]];
SetBBox[curveX+minX, curveY+minY, maxX-minX, maxY-minY];
pressHandle.PutCubic[cX, cY, bX, bY, aX, aY];
};
IF skipAlternative THEN RETURN;
pressHandle.StartOutline;
pressFile.GetObject[moveToProc, drawToProc, drawCurveProc];
pressHandle.EndOutline;
}; -- showObjectProc
showDotsProc: PressReader.ShowDotsProc = {
codingType, dotsPerLine, scanLines, passDots, displayDots, passLines, displayLines: INT ← 0;
scanMode: CARDINAL ← 0;
windowWidth, windowHeight: INT ← 0;
dotInfo: PressReader.Dots;
setCodingProc: PressReader.SetCodingProc = {
codingType ← code;
windowWidth ← dotsPerLine ← displayDots ← dots;
windowHeight ← scanLines ← displayLines ← lines;
};
setModeProc: PressReader.SetModeProc = {scanMode ← mode};
setWindowProc: PressReader.SetWindowProc = {
passDots ← pd;
displayDots ← dd;
passLines ← pl;
displayLines ← dl;
};
setSizeProc: PressReader.SetSizeProc = {
windowWidth ← width;
windowHeight ← height;
};
dotsFollowProc: PressReader.DotsFollowProc = {
dotInfo ← dots;
};
ScratchRec: TYPE ~ RECORD [SEQUENCE length: NAT OF WORD];
scratch: REF ScratchRec;
bytesPerLine: INT ← 0;
IF skipAlternative THEN RETURN;
pressFile.GetDots[setCoding: setCodingProc, setMode: setModeProc,
setWindow: setWindowProc, setSize: setSizeProc, dotsFollow: dotsFollowProc];
scratch ← NEW[ScratchRec[(dotsPerLine+3)/2]];
SetBBox[x, y, windowWidth, windowHeight];
pressHandle.BeginScannedRectangle[
x: x, y: y,
dotsPerLine: dotsPerLine,
numberOfLines: scanLines,
width: windowWidth,
height: windowHeight,
nextLineDirection: LOOPHOLE[scanMode MOD 4],
nextDotDirection: LOOPHOLE[scanMode / 4],
coding: SELECT codingType FROM
0 => bitMap,
1 => bitSampled,
2 => bitBitSampled,
4 => nybbleSampled,
8 => byteSampled,
ENDCASE => ERROR
];
bytesPerLine ← (MAX[codingType, 1] * dotsPerLine + 7)/8;
scratch[bytesPerLine/2] ← 0; -- make sure array is big enough
dotInfo.file.SetIndex[dotInfo.pageNumber*bytesPerPage+dotInfo.byteOffset];
FOR i: INT IN [0..scanLines) DO
TRUSTED {[] ← dotInfo.file.UnsafeGetBlock[[base: (LOOPHOLE[@scratch[0]]), startIndex: 0, count: bytesPerLine]]};
TRUSTED {pressHandle.UnsafeShowLine[@scratch[0]]};
ENDLOOP;
pressHandle.EndScannedRectangle;
}; -- showDotsProc
fontProc[0];
pressHandle.SetColor[0, 0, 0];
pressFile.GetCommands[
showCharactersProc: showCharactersProc,
fontProc: fontProc,
positionProc: positionProc,
spacingProc: spacingProc,
spaceProc: spaceProc,
colorProc: colorProc,
showRectangleProc: showRectangleProc,
alternativeProc: alternativeProc,
showObjectProc: showObjectProc,
showDotsProc: showDotsProc
];
}; -- EntityProc
pressFile.GetPage[EntityProc];
}; -- PageProc
SkipFonts: PressReader.FontDirectoryProc = {
ok ← FALSE;
};
pressFile.GetParts[pageNumber, PageProc, SkipFonts];
RETURN [leftMax, topMax, rightMax, bottomMax, ok];
};
FindBBox: PUBLIC PROC [pressFileName: ROPE] RETURNS[left, top, right, bottom: INT, ok: BOOLEAN] ~ {
pressFile: PressReader.Handle ← PressReader.OpenPressFile[pressFileName];
documentDirectory: PressReader.DocumentDirectory ← pressFile.GetDocumentDirectory;
pageNumber: INT ← 1;
fontTable: REF ARRAY [0..6*16) OF PressReader.FontDirectoryEntry ← NEW[ARRAY [0..6*16) OF PressReader.FontDirectoryEntry];
FontInitProc: PressReader.FontEntryProc = { -- build a list of needed fonts
fontTable[fontDirectoryEntry.fontSet*16 + fontDirectoryEntry.font] ← fontDirectoryEntry;
}; -- FontInitProc
pressFile.GetFonts[FontInitProc];
[left, top, right, bottom, ok] ← FindBBoxPage[pressFile, pageNumber, fontTable] ;
pressFile.ClosePressFile[];
RETURN [left, top, right, bottom, ok];
};
PressBBoxCommand: Commander.CommandProc ~ {
stream: IO.STREAMIO.RIS[cmd.commandLine];
GetToken: PROC RETURNS [rope: ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token;
};
pressFileName: ROPE ← GetToken[];
Pt: PROC [p: INT] RETURNS [INT] ~ {
micasPerPt: REAL ~ (2540/72.0);
RETURN[Real.RoundLI[p/micasPerPt]];
};
left, top, right, bottom: INT;
ok: BOOLEAN;
IF pressFileName.IsEmpty THEN {
cmd.out.PutRope["Specify press file please"];
RETURN};
IF pressFileName.Find[".press", 0, FALSE] = -1 THEN {
pressFileName ← pressFileName.Concat[".press"];
};
[left, top, right, bottom, ok] ← FindBBox[pressFileName];
cmd.out.PutRope[pressFileName];
cmd.out.PutRope[IO.PutFR[" leftMargin: %g pt, topMargin: %g pt, width: %g pt, height: %g pt\n", IO.int[Pt[left]], IO.int[Pt[(11*2540)-top]], IO.int[Pt[right-left]], IO.int[Pt[top-bottom]]]];
IF GetToken[].Length # 0 THEN {cmd.out.PutRope["Ignored: "]; cmd.out.PutRope[cmd.commandLine.Substr[stream.GetIndex]]; cmd.out.PutChar['\n]};
};
Commander.Register["PressOverlay", PressOverlayCommand, "Overlay two press files on each other (output ← input1 input2)"];
Commander.Register["PressBBox", PressBBoxCommand, "Finds the bounding box margins for the press file, suitable for IncludePress nodes"];
END.