<> <> <> <> 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: BOOLEAN _ TRUE] = { 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: BOOL _ FALSE; reposition: BOOLEAN _ FALSE; 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: ROPE _ NIL; 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.STREAM _ IO.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: INT _ LAST[INT]; topMax: INT _ FIRST[INT]; rightMax: INT _ FIRST[INT]; bottomMax: INT _ LAST[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 <> <> <> skipAlternative, inAlternative: BOOL _ FALSE; reposition: BOOLEAN _ FALSE; showCharactersProc: PressReader.ShowCharactersProc = { widthOfText: INT _ 1; heightOfText: INT _ 1; IF skipAlternative THEN RETURN; IF reposition THEN { SetBBox[x, y, widthOfText, heightOfText]; <> reposition _ FALSE} ELSE { SetBBox[x, y, widthOfText, heightOfText]; <> }; }; -- showCharactersProc fontProc: PressReader.FontProc = { IF skipAlternative THEN RETURN; currentFont _ fontTable[entityTrailer.fontSet*16+font]; <> <> }; 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; <> }; spaceProc: PressReader.SpaceProc = { showCharactersProc[showCharacterImmediate, 1, " "]; }; colorProc: PressReader.ColorProc = { IF skipAlternative THEN RETURN; <