<> <> <> <> <> <> <> <<>> DIRECTORY Convert USING [AppendInt], Imager USING [black, Context, DoSave, MaskFill, MaskRectangle, SetColor, SetFont, SetGray, SetXY, SetXRel, SetXYRel, SetYRel, Show, TranslateT], ImagerColor USING [ColorFromRGB, RGBFromHSV], ImagerBackdoor USING [GetCP, DoIfVisible], ImagerFont USING [Escapement, Extents, Find, Font, FontBoundingBox, Modify, Scale, XChar], ImagerPath USING [PathProc], ImagerTransformation USING [Rotate], PressImage USING [DrawPressImage, MakePressImage, PressImage, PressImageError], PressReader USING [AlternativeProc, ClosePressFile, ColorProc, Dots, DotsFollowProc, DrawCurveProc, DrawToProc, EntityProc, FontDirectoryProc, FontEntryProc, FontFace, FontProc, GetCommands, GetDocumentDirectory, GetDots, GetFonts, GetObject, GetPage, GetParts, Handle, MoveToProc, OpenPressFile, PageProc, PositionProc, PressReaderError, SetCodingProc, SetModeProc, SetSamplingPropertiesProc, SetSizeProc, SetWindowProc, ShowCharactersProc, ShowDotsProc, ShowObjectProc, ShowRectangleProc, SpaceProc, SpacingProc], Real USING [Round, LargestNumber], RefText USING [AppendChar, AppendRope, ObtainScratch, ReleaseScratch], Rope USING [Fetch, FromRefText, Map, ROPE, Size], ShowPress USING [FontRec, PressFileRec], Vector2 USING [Add, Div, Mul, Sub, VEC]; ShowPressImpl: CEDAR PROGRAM IMPORTS Convert, Imager, ImagerBackdoor, ImagerColor, ImagerFont, ImagerTransformation, PressImage, PressReader, Real, RefText, Rope, Vector2 EXPORTS ShowPress = BEGIN ROPE: TYPE ~ Rope.ROPE; Handle: TYPE ~ REF PressFileRec; PressFileRec: TYPE ~ ShowPress.PressFileRec; FontRec: TYPE ~ ShowPress.FontRec; nullReal: REAL _ -Real.LargestNumber; micasPerPoint: REAL _ 2540.0/72.0; pointsPerMica: REAL _ 72.0/2540.0; ShowPressError: PUBLIC ERROR [code: ATOM] = CODE; Coeffs: TYPE = RECORD [c0, c1, c2, c3: Vector2.VEC]; Bezier: TYPE = RECORD [b0, b1, b2, b3: Vector2.VEC]; SetHSV: PROC [context: Imager.Context, h, s, v: REAL] = { IF v = 0.0 THEN { Imager.SetColor[context, Imager.black]; } ELSE { IF s = 0.0 THEN { Imager.SetGray[context, 1.0-v]; } ELSE { Imager.SetColor[context, ImagerColor.ColorFromRGB[ImagerColor.RGBFromHSV[[H: h, S: s, V: v]]]]; }; }; }; CoeffsToBezier: PROC [coeffs: Coeffs] RETURNS [bezier: Bezier] = { <> <> <> <> <> <> <> bezier.b0 _ coeffs.c0; bezier.b1 _ coeffs.c0.Add[coeffs.c1.Div[3]]; bezier.b2 _ bezier.b1.Add[coeffs.c1.Add[coeffs.c2].Div[3]]; bezier.b3 _ coeffs.c0.Add[coeffs.c1].Add[coeffs.c2].Add[coeffs.c3]; RETURN[bezier]; }; BezierToCoeffs: PROC [bezier: Bezier] RETURNS [coeffs: Coeffs] = { <> <> <> <> <> t: Vector2.VEC _ bezier.b2.Sub[bezier.b1].Mul[3]; coeffs.c0 _ bezier.b0; coeffs.c1 _ bezier.b1.Sub[bezier.b0].Mul[3]; coeffs.c2 _ t.Sub[coeffs.c1]; coeffs.c3 _ bezier.b3.Sub[bezier.b0.Add[t]]; RETURN[coeffs]; }; NameFromPressFontID: PROC [family: ROPE, face: PressReader.FontFace] RETURNS [name: ROPE] ~ { t: REF TEXT _ RefText.ObtainScratch[100]; t _ RefText.AppendRope[t, "Xerox/Pressfonts/"]; t _ RefText.AppendRope[t, family]; IF face.texDesignSize > 0 THEN { t _ Convert.AppendInt[t, Real.Round[face.texDesignSize]]; } ELSE { t _ RefText.AppendChar[t, '-]; t _ RefText.AppendChar[t, SELECT face.weight FROM medium => 'M, bold => 'B, light => 'L, ENDCASE => 'M ]; t _ RefText.AppendChar[t, SELECT face.slope FROM regular => 'R, italic => 'I, ENDCASE => 'R ]; t _ RefText.AppendChar[t, SELECT face.expansion FROM regular => 'R, condensed => 'C, expanded => 'E, ENDCASE => 'R ]; }; name _ Rope.FromRefText[t]; RefText.ReleaseScratch[t]; }; Open: PUBLIC PROCEDURE [fileName: Rope.ROPE] RETURNS [show: Handle _ NIL] = { FontInitProc: PressReader.FontEntryProc = { -- build a list of needed fonts sizeInMicas: REAL ~ ( IF fontDirectoryEntry.size > 0 THEN ((REAL[fontDirectoryEntry.size]*2540.0)/72.0) ELSE (REAL[-fontDirectoryEntry.size]) ); name: ROPE ~ NameFromPressFontID[fontDirectoryEntry.family, fontDirectoryEntry.face]; imagerFont: ImagerFont.Font _ ImagerFont.Scale[ImagerFont.Find[name], sizeInMicas]; IF fontDirectoryEntry.rotation#0 THEN { degrees: REAL _ fontDirectoryEntry.rotation/60.0; imagerFont _ ImagerFont.Modify[imagerFont, ImagerTransformation.Rotate[degrees]]; }; show.fontTable[fontDirectoryEntry.fontSet*16+fontDirectoryEntry.font] _ [ imagerFont: imagerFont, family: fontDirectoryEntry.family, face: fontDirectoryEntry.face.encoding, size: sizeInMicas, rotation: REAL[fontDirectoryEntry.rotation]/60.0 ]; }; -- FontInitProc pressFile: PressReader.Handle _ PressReader.OpenPressFile[fileName ! PressReader.PressReaderError => { SELECT errorCode FROM FileNotAPressFile => ERROR ShowPressError[$CantReadFile]; ENDCASE => REJECT; } ]; show _ NEW[PressFileRec]; show.pressFile _ pressFile; show.lastPart _ pressFile.GetDocumentDirectory[].nParts; show.pressFile.GetFonts[FontInitProc]; }; DrawPressPage: PUBLIC PROCEDURE [context: Imager.Context, show: Handle, pageNumber: INT, tinyPaint: BOOL _ FALSE] = { skipAlternative: BOOL _ FALSE; hue: REAL _ 0.0; saturation: REAL _ 0.0; brightness: REAL _ 0.0; colorChanged: BOOL _ TRUE; ValidateColor: PROC ~ { IF colorChanged THEN { IF saturation = 0 THEN Imager.SetGray[context, 1.0-brightness] ELSE SetHSV[context, hue, saturation, brightness]; colorChanged _ FALSE; }; }; showObjectProc: PressReader.ShowObjectProc = { IF NOT skipAlternative THEN { Path: ImagerPath.PathProc ~ { lp: Vector2.VEC _ [0, 0]; moveToProc: PressReader.MoveToProc = {moveTo[lp _ [x, y]]}; drawToProc: PressReader.DrawToProc = {lineTo[lp _ [x, y]]}; drawCurveProc: PressReader.DrawCurveProc = { cubic: Coeffs ~ [c0: lp, c1: [cX, cY], c2: [bX, bY], c3: [aX, aY]]; bezier: Bezier ~ CoeffsToBezier[cubic]; curveTo[bezier.b1, bezier.b2, bezier.b3]; lp _ bezier.b3; }; show.pressFile.GetObject[moveToProc, drawToProc, drawCurveProc]; }; ValidateColor[]; Imager.MaskFill[context: context, path: Path, oddWrap: TRUE] }; }; -- showObjectProc PageProc: PressReader.PageProc = { EntityProc: PressReader.EntityProc = { -- Xe, Ye, fontSet currentFont: FontRec; -- will be established by setFont currentFontYMin, currentFontYMax: REAL; -- for faster culling of characters currentSpaceX: REAL; -- will be established by setFont currentSpaceY: REAL; -- will be established by setFont spaceChanged: BOOL _ FALSE; x, y: REAL _ 0.0; cpChanged: BOOL _ TRUE; inAlternative: BOOL _ FALSE; ValidateCP: PROC ~ { IF cpChanged THEN { IF x = nullReal THEN x _ ImagerBackdoor.GetCP[context].x; IF y = nullReal THEN y _ ImagerBackdoor.GetCP[context].y; Imager.SetXY[context, [x, y]]; cpChanged _ FALSE; }; }; showCharactersProc: PressReader.ShowCharactersProc = { ShowAction: PROC ~ { start: INT _ 0; size: INT ~ Rope.Size[text]; WHILE start> textYMax: REAL ~ y + currentFontYMax; textYMin: REAL ~ y + currentFontYMin; ImagerBackdoor.DoIfVisible[context, [x: 0, y: textYMin, w: 32768, h: textYMax-textYMin], ShowAction]; } ELSE ShowAction[]; x _ nullReal; IF currentFont.rotation # 0 THEN y _ nullReal; }; -- showCharactersProc fontProc: PressReader.FontProc = { IF skipAlternative THEN RETURN; currentFont _ show.fontTable[entityTrailer.fontSet*16+font]; IF currentFont.imagerFont # NIL THEN { extents: ImagerFont.Extents ~ ImagerFont.FontBoundingBox[currentFont.imagerFont]; currentFontYMin _ -extents.descent; currentFontYMax _ extents.ascent; } ELSE { currentFontYMin _ FIRST[INTEGER]; currentFontYMax _ LAST[INTEGER]; }; IF currentFont.imagerFont = NIL THEN RETURN; Imager.SetFont[context, currentFont.imagerFont]; }; positionProc: PressReader.PositionProc = { IF skipAlternative THEN RETURN; SELECT opCode FROM setX => { IF cpChanged THEN NULL ELSE IF x=nullReal THEN cpChanged _ TRUE ELSE Imager.SetXRel[context, value-x]; x _ value; }; setY => { IF cpChanged THEN NULL ELSE IF y=nullReal THEN cpChanged _ TRUE ELSE Imager.SetYRel[context, value-y]; y _ value; }; ENDCASE => ERROR; }; spacingProc: PressReader.SpacingProc = { IF skipAlternative THEN RETURN; IF opCode#resetSpace AND NOT spaceChanged THEN { IF currentFont.imagerFont=NIL THEN ERROR ShowPressError[$NoCurrentFont]; [[currentSpaceX, currentSpaceY]] _ ImagerFont.Escapement[currentFont.imagerFont, [set:0,code:ORD[' ]]]; spaceChanged _ TRUE; }; SELECT opCode FROM setSpaceX, setSpaceXShort => currentSpaceX _ value; setSpaceY, setSpaceYShort => currentSpaceY _ value; resetSpace => spaceChanged _ FALSE; ENDCASE => ERROR; }; spaceProc: PressReader.SpaceProc = { IF skipAlternative THEN RETURN; showCharactersProc[opCode: showCharacterImmediate, length: 1, text: "\040"]; }; colorProc: PressReader.ColorProc = { IF skipAlternative THEN RETURN; SELECT opCode FROM setHue => hue _ REAL[value MOD 240]/240.0; setSaturation => saturation _ REAL[value]/255.0; setBrightness => brightness _ REAL[value]/255.0; ENDCASE => ERROR; colorChanged _ TRUE; }; showRectangleProc: PressReader.ShowRectangleProc = { IF skipAlternative THEN RETURN; IF x = nullReal THEN x _ ImagerBackdoor.GetCP[context].x; IF y = nullReal THEN y _ ImagerBackdoor.GetCP[context].y; ValidateColor[]; Imager.MaskRectangle[context, [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; }; showDotsProc: PressReader.ShowDotsProc = { codingType, dotsPerLine, scanLines, scanMode, passDots, displayDots, passLines, displayLines: INT _ 0; windowWidth, windowHeight: REAL _ 0.0; dotInfo: PressReader.Dots; image: PressImage.PressImage; <> 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 _ REAL[width]; windowHeight _ REAL[height]; }; setSampling: PressReader.SetSamplingPropertiesProc = { <<[samplingProperties: LIST OF PressReader.SamplingProperty]>> <> }; dotsFollowProc: PressReader.DotsFollowProc = { dotInfo _ dots; }; IF skipAlternative THEN RETURN; show.pressFile.GetDots[setCodingProc, setModeProc, setWindowProc, setSizeProc, setSampling, dotsFollowProc]; <<{>> <<-- Cull dots obviously outside the context>> <> <> <<[cpX, cpY] _ Graphics.GetCP[context];>> < cpY+(windowHeight*micasPerPoint) THEN>> <> <<};>> { image _ PressImage.MakePressImage[ sampleType: codingType, dots: dotsPerLine, lines: scanLines, mode: scanMode, pd: passDots, dd: displayDots, pl: passLines, dl: displayLines, width: windowWidth, height: windowHeight, bits: dotInfo ! PressImage.PressImageError => GOTO Quit ]; ValidateCP[]; PressImage.DrawPressImage[context, image]; }; EXITS Quit => RETURN; }; -- showDotsProc skipAlternative _ FALSE; hue _ saturation _ brightness _ 0.0; colorChanged _ TRUE; Imager.TranslateT[context, [entityTrailer.Xe, entityTrailer.Ye]]; fontProc[0]; -- SetFont 0; ResetSpace; Imager.SetXY[context, [0, 0]]; show.pressFile.GetCommands[ showCharactersProc: showCharactersProc, fontProc: fontProc, positionProc: positionProc, spacingProc: spacingProc, spaceProc: spaceProc, colorProc: colorProc, showRectangleProc: showRectangleProc, alternativeProc: alternativeProc, showObjectProc: showObjectProc, showDotsProc: showDotsProc ]; }; -- EntityProc OuterEntityProc: PressReader.EntityProc ~ { proc: PROC ~ {EntityProc[handle, entityTrailer]}; Imager.DoSave[context, proc]; }; show.pressFile.GetPage[OuterEntityProc]; }; -- PageProc SkipFonts: PressReader.FontDirectoryProc = { pageNumber _ IF pageNumber = show.lastPart THEN ERROR ShowPressError[$NoSuchPage] ELSE MIN[pageNumber+1, show.lastPart]; show.pressFile.GetParts[pageNumber, PageProc, SkipFonts]; }; <<[] _ Graphics.SetFat[self: context, fat: TRUE];>> show.pressFile.GetParts[pageNumber, PageProc, SkipFonts]; }; -- DrawPressPage Close: PUBLIC PROCEDURE [show: Handle] = TRUSTED { show.pressFile.ClosePressFile[]; }; END. <> <<>> <> <<>> <> <> <<>> <> <> <<>> <> <> <> <<>> <> <> <<>> <> <> <<>> <<>> <> <> <> <<>> <<>> <<>>