DIRECTORY CGCubic USING [Bezier, Coeffs, CoeffsToBezier, Flat, Split], GraphicsBasic USING [Vec], GraphicsColor USING [HSVToColor, ColorToIntensity], IPEncodingOut USING [AppendInteger, AppendOp], IPLimits USING [topFrameSize], IPOperatorOut, IPVariables USING [FrameVariable, ImagerVariable], List USING [Comparison, CompareProc, Sort, Cons], PressFontReader USING [Close, Font, FontInfoRec, FromFile, Handle, ListFonts], PressToIP, PressReader, Real USING [RoundI, RoundLI], Rope USING [Cat, Equal, Fetch, Find, Length, ROPE]; PressToIPImpl: PROGRAM IMPORTS CGCubic, GraphicsColor, IPEncodingOut, IP: IPOperatorOut, List, PressFontReader, PressReader, Real, Rope EXPORTS PressToIP = BEGIN OPEN PressToIP; Positioning: TYPE = {relative, absolute}; Spacing: TYPE = {amplifying1, amplifying2, positioning}; OpenPressFile: PUBLIC PROCEDURE [pressFileName: Rope.ROPE] RETURNS [pressFile: PressFile] = { pressFile _ PressReader.OpenPressFile[pressFileName ! PressReader.PressReaderError => SELECT errorCode FROM FileNotAvailableForRead, AbortedBecauseGetFailed => ERROR Error[FileNotAvailable]; FileNotAPressFile => ERROR Error[FileNotAPressFile]; ENDCASE => REJECT ]; }; OpenOutputIPMaster: PUBLIC PROCEDURE [ipMasterName: Rope.ROPE] RETURNS [ipMaster: IPMaster] = { ipMaster _ IP.BeginMaster[ipMasterName ! IP.Error => ERROR Error[FileNotAvailable] ]; }; Font: TYPE = REF FontRec; FontRec: TYPE = RECORD[ encoding: NAT, -- fontSet*16+fontNumber, from Press file fontNumber: NAT, -- font number in Interpress master family: Rope.ROPE, faceCode: Rope.ROPE, sizeInMicas: INT, rotation: INTEGER, -- in minutes of arc widthX, widthY: REF WidthArray, fixedWidthX, fixedWidthY: INTEGER ]; WidthArray: TYPE = ARRAY CHAR OF INTEGER; Fonts: TYPE = RECORD[SEQUENCE max: NAT OF Font]; WidthX: PROC[f: Font, c: CHAR] RETURNS[INTEGER] = INLINE { RETURN[IF f.widthX=NIL THEN f.fixedWidthX ELSE f.widthX[c]] }; WidthY: PROC[f: Font, c: CHAR] RETURNS[INTEGER] = INLINE { RETURN[IF f.widthY=NIL THEN f.fixedWidthY ELSE f.widthY[c]] }; ConvertPressToInterpress: PUBLIC PROC[pressFile: PressFile, ipMaster: IPMaster, usePriority: BOOLEAN _ FALSE, fullInterpress: BOOLEAN _ FALSE, progressProc: ProgressProc _ NIL, progressData: REF ANY] = { fonts: REF Fonts; nFonts: INT _ 0; tooManyFontsForFrame: BOOLEAN; fontSets: INT _ 0; -- number of auxiliary composed operators/frames needed to hold >50 fonts PageProc: PressReader.PageProc = { ipGray: REAL _ 1.0; -- current gray in the Interpress master ipAmplify: REAL _ 1.0; -- current amplifySpace value in the Interpress master EntityProc: PressReader.EntityProc = { -- Xe, Ye, fontSet Xe: INTEGER = entityTrailer.Xe; Ye: INTEGER = entityTrailer.Ye; hue, saturation, brightness: INT _ 0; -- current color in the Press file fontNum: NAT _ 0; -- current font number unset: INTEGER = FIRST[INTEGER]; spaceX, spaceY: INTEGER _ unset; -- current space width pX, pY: INTEGER _ 0; -- current (entity-relative) position in the Press file newPosition: BOOL _ TRUE; -- new position set, not yet reflected in IP master newFont: BOOL _ TRUE; -- new font number set, curFont not yet updated newAmplify: BOOL _ TRUE; -- amplifySpace must be recomputed newColor: BOOL _ TRUE; -- new color set, not yet reflected in IP master curFont: Font _ NIL; -- current font (if ~newFont) skippingAlternative, inAlternative: BOOLEAN _ FALSE; SetPosition: PROC = { ipMaster.SetXY[IP.int[pX+Xe], IP.int[pY+Ye]]; newPosition _ FALSE; }; SetFont: PROC = { key: NAT = entityTrailer.fontSet*16+fontNum; IF skippingAlternative THEN RETURN; IF nFonts=0 THEN RETURN; IF curFont=NIL OR curFont.encoding#key THEN { l: NAT _ 0; u: NAT _ nFonts; WHILE l <= u DO i: NAT = (l+u)/2; f: Font = fonts[i]; SELECT f.encoding FROM > key => u _ i-1; < key => l _ i+1; = key => { curFont _ f; EXIT }; ENDCASE; REPEAT FINISHED => ERROR Error[FontNotFound]; ENDLOOP; IF tooManyFontsForFrame THEN { ipMaster.FGet[IPVariables.FrameVariable[0]]; ipMaster.Get[curFont.fontNumber]; ipMaster.AppendInteger[ LOOPHOLE[IPVariables.ImagerVariable[showVec], CARDINAL]]; ipMaster.AppendOp[iset]; } ELSE ipMaster.SetFont[curFont.fontNumber]; }; newFont _ FALSE; newAmplify _ TRUE; }; SetAmplify: PROC = { sX, sY, dX, dY, s, d: INTEGER; amplify: REAL; IF newFont THEN SetFont[]; dX _ WidthX[curFont, ' ]; dY _ WidthY[curFont, ' ]; sX _ (IF spaceX=unset THEN dX ELSE spaceX); sY _ (IF spaceY=unset THEN dY ELSE spaceY); IF sY=0 AND dY=0 THEN { s _ sX; d _ dX } ELSE IF sX=0 AND dX=0 THEN { s _ sY; d _ dY } ELSE ERROR; -- not implemented amplify _ REAL[s]/REAL[d]; IF amplify#ipAmplify THEN { ipMaster.SetAmplifySpace[IF s=d THEN IP.int[1] ELSE IP.rational[s, d]]; ipAmplify _ amplify; }; newAmplify _ FALSE; }; SetColor: PROC = { h: REAL = hue/255.0; s: REAL = saturation/255.0; v: REAL = brightness/255.0; i: REAL = GraphicsColor.ColorToIntensity[GraphicsColor.HSVToColor[h, s, v]]; gray: REAL = 1.0-i; IF gray#ipGray THEN ipMaster.SetGray[IP.real[ipGray _ gray]]; newColor _ FALSE; }; showCharactersProc: PressReader.ShowCharactersProc = { -- [opCode, length, text] HasSpaces: PROC[rope: Rope.ROPE] RETURNS[BOOL] = INLINE { RETURN[rope.Find[" "]>=0] }; IF skippingAlternative THEN RETURN; IF newColor THEN SetColor[]; IF newPosition THEN SetPosition[]; IF newFont THEN SetFont[]; -- Note: may set newAmplify IF newAmplify AND HasSpaces[text] THEN SetAmplify[]; ipMaster.Show[text]; FOR i: INT IN[0..text.Length[]) DO c: CHAR = text.Fetch[i]; IF c=' THEN { pX _ pX+(IF spaceX=unset THEN WidthX[curFont, ' ] ELSE spaceX); pY _ pY+(IF spaceY=unset THEN WidthY[curFont, ' ] ELSE spaceY); } ELSE { pX _ pX+WidthX[curFont, c]; pY _ pY+WidthY[curFont, c]; }; ENDLOOP; }; spacingProc: PressReader.SpacingProc = { -- [opCode, value] IF skippingAlternative THEN RETURN; IF value=unset THEN ERROR; SELECT opCode FROM setSpaceX, setSpaceXShort => spaceX _ value; setSpaceY, setSpaceYShort => spaceY _ value; resetSpace => spaceX _ spaceY _ unset; ENDCASE => ERROR; newAmplify _ TRUE; }; spaceProc: PressReader.SpaceProc = { -- [] sX, sY: INTEGER; IF skippingAlternative THEN RETURN; IF newFont THEN SetFont[]; sX _ (IF spaceX=unset THEN WidthX[curFont, ' ] ELSE spaceX); sY _ (IF spaceY=unset THEN WidthY[curFont, ' ] ELSE spaceY); SELECT TRUE FROM sY=0 => ipMaster.SetXRel[IP.int[sX]]; sX=0 => ipMaster.SetYRel[IP.int[sY]]; ENDCASE => ipMaster.SetXYRel[IP.int[sX], IP.int[sY]]; pX _ pX+sX; pY _ pY+sY; }; positionProc: PressReader.PositionProc = { IF skippingAlternative THEN RETURN; SELECT opCode FROM setX => pX _ value; setY => pY _ value; ENDCASE => ERROR; newPosition _ TRUE; }; colorProc: PressReader.ColorProc = { IF skippingAlternative THEN RETURN; SELECT opCode FROM setHue => hue _ value; setSaturation => saturation _ value; setBrightness => brightness _ value; ENDCASE => ERROR; newColor _ TRUE; }; fontProc: PressReader.FontProc = { -- [font] IF font#fontNum THEN { fontNum _ font; newFont _ TRUE }; }; -- fontProc alternativeProc: PressReader.AlternativeProc = { IF (types = 0) AND (elBytes = 0) AND (dlBytes = 0) THEN inAlternative _ skippingAlternative _ FALSE ELSE IF inAlternative THEN skippingAlternative _ TRUE ELSE inAlternative _ TRUE; }; showObjectProc: PressReader.ShowObjectProc = { nTrajectories: INT _ 0; CurveFlatten: PROCEDURE [curve: CGCubic.Bezier] = { c1, c2: CGCubic.Bezier; IF CGCubic.Flat[curve, 1.5] THEN { x: INT = Real.RoundLI[curve.b3.x]; y: INT = Real.RoundLI[curve.b3.y]; ipMaster.LineTo[IP.int[x], IP.int[y]] } ELSE { [c1, c2] _ CGCubic.Split[curve]; CurveFlatten[c1]; CurveFlatten[c2]; }; }; -- CurveFlatten moveToProc: PressReader.MoveToProc = { pX _ entityTrailer.Xe+x; pY _ entityTrailer.Ye+y; ipMaster.MoveTo[IP.int[pX], IP.int[pY]]; nTrajectories _ nTrajectories+1; }; drawToProc: PressReader.DrawToProc = { xNew: INT _ entityTrailer.Xe+x; yNew: INT _ entityTrailer.Ye+y; IF (xNew = pX) AND (yNew = pY) THEN RETURN ELSE IF yNew = pY THEN ipMaster.LineToX[IP.int[xNew]] ELSE IF xNew = pX THEN ipMaster.LineToY[IP.int[yNew]] ELSE ipMaster.LineTo[IP.int[xNew], IP.int[yNew]]; pX _ xNew; pY _ yNew; }; drawCurveProc: PressReader.DrawCurveProc = { -- note: Full IP has CurveTo bezier: CGCubic.Bezier; bezier _ CGCubic.CoeffsToBezier[CGCubic.Coeffs[ c0: GraphicsBasic.Vec[REAL[pX], REAL[pY]], c1: GraphicsBasic.Vec[cX, cY], c2: GraphicsBasic.Vec[bX, bY], c3: GraphicsBasic.Vec[aX, aY]]]; IF fullInterpress THEN { x1, y1, x2, y2, x3, y3: INT; x1 _ Real.RoundLI[bezier.b1.x]; y1 _ Real.RoundLI[bezier.b1.y]; x2 _ Real.RoundLI[bezier.b2.x]; y2 _ Real.RoundLI[bezier.b2.y]; x3 _ Real.RoundLI[bezier.b3.x]; y3 _ Real.RoundLI[bezier.b3.y]; ipMaster.CurveTo[ IP.int[x1], IP.int[y1], IP.int[x2], IP.int[y2], IP.int[x3], IP.int[y3]]; pX _ x3; pY _ y3; } ELSE { CurveFlatten[bezier]; pX _ Real.RoundLI[bezier.b3.x]; pY _ Real.RoundLI[bezier.b3.y]; }; }; -- drawCurveProc IF skippingAlternative THEN RETURN; IF newColor THEN SetColor[]; pressFile.GetObject[[moveToProc, drawToProc, drawCurveProc]]; ipMaster.AppendInteger[nTrajectories]; ipMaster.AppendOp[makeoutline]; ipMaster.AppendOp[maskfill]; }; -- showObjectProc showRectangleProc: PressReader.ShowRectangleProc = { IF skippingAlternative THEN RETURN; IF newColor THEN SetColor[]; ipMaster.MaskRectangle[IP.int[pX+Xe], IP.int[pY+Ye], IP.int[width], IP.int[height]]; }; pressFile.GetCommands[PressReader.CommandProcs[ showCharactersProc: showCharactersProc, spacingProc: spacingProc, spaceProc: spaceProc, positionProc: positionProc, colorProc: colorProc, fontProc: fontProc, alternativeProc: alternativeProc, showObjectProc: showObjectProc, showRectangleProc: showRectangleProc ]]; }; -- EntityProc ipMaster.BeginPage[]; ipMaster.Scale[IP.real[1.0E-5]]; -- scale to Press units (micas) IF usePriority THEN ipMaster.SetPriorityImportant[TRUE]; pressFile.GetPage[EntityProc]; ipMaster.EndPage[]; IF progressProc # NIL THEN progressProc[page, progressData]; }; -- PageProc LoadFonts: PROCEDURE = { fontFile: PressFontReader.Handle _ PressFontReader.FromFile[ "/Indigo/Interpress/Fonts/InterpressFonts.Widths"]; pressFonts: LIST OF PressFontReader.Font _ PressFontReader.ListFonts[fontFile]; fontList: LIST OF REF ANY _ NIL; fontName: Rope.ROPE; f: NAT _ 0; FontInitProc: PressReader.FontEntryProc = { -- fontDirectoryEntry pressFont: PressFontReader.Font _ NIL; fontInfo: PressFontReader.FontInfoRec; sizeInMicas: INTEGER = IF fontDirectoryEntry.size < 0 THEN -fontDirectoryEntry.size ELSE Real.RoundI[fontDirectoryEntry.size*(2540.0/72.0)]; -- convert points to micas FOR list: LIST OF PressFontReader.Font _ pressFonts, list.rest UNTIL list=NIL DO pressFont _ list.first; fontInfo _ pressFont.info; IF Rope.Equal[fontInfo.family, fontDirectoryEntry.family, FALSE] AND (fontInfo.face = fontDirectoryEntry.face.encoding) AND ((fontInfo.size = 0) OR (Real.RoundLI[fontInfo.size*1.0E5] = sizeInMicas)) AND ((fontInfo.rotation = fontDirectoryEntry.rotation)) THEN EXIT; REPEAT FINISHED => ERROR Error[FontNotFound]; -- couldn't find correct press font ENDLOOP; WITH fp: pressFont.private SELECT FROM widthsOnly => { font: Font = NEW[FontRec _ [encoding: 0, fontNumber: 0, family: NIL, faceCode: NIL, sizeInMicas: 0, rotation: 0, widthX: NIL, widthY: NIL, fixedWidthX: 0, fixedWidthY: 0]]; font.encoding _ fontDirectoryEntry.fontSet*16+fontDirectoryEntry.font; font.family _ fontInfo.family; font.faceCode _ Rope.Cat[ SELECT fontDirectoryEntry.face.weight FROM medium => "M", bold => "B", light => "L", ENDCASE => ERROR, SELECT fontDirectoryEntry.face.slope FROM regular => "R", italic => "I", ENDCASE => ERROR, SELECT fontDirectoryEntry.face.expansion FROM regular => "R", condensed => "C", expanded => "E", ENDCASE => ERROR]; font.sizeInMicas _ sizeInMicas; font.rotation _ fontDirectoryEntry.rotation; IF fontInfo.rotation#0 THEN ERROR; -- worry about this later ... IF fp.widthSeg.XWidthFixed THEN font.fixedWidthX _ fp.xWidthDesc[0] ELSE { widthX: REF WidthArray = NEW[WidthArray _ ALL[0]]; FOR c: CHAR IN[fontInfo.bc..fontInfo.ec] DO w: INTEGER = LOOPHOLE[fp.xWidthDesc[c-fontInfo.bc]]; IF w#FIRST[INTEGER] THEN widthX[c] _ w; ENDLOOP; font.widthX _ widthX; }; IF fp.widthSeg.YWidthFixed THEN font.fixedWidthY _ fp.yWidthDesc[0] ELSE { widthY: REF WidthArray = NEW[WidthArray _ ALL[0]]; FOR c: CHAR IN[fontInfo.bc..fontInfo.ec] DO w: INTEGER = LOOPHOLE[fp.yWidthDesc[c-fontInfo.bc]]; IF w#FIRST[INTEGER] THEN widthY[c] _ w; ENDLOOP; font.widthY _ widthY; }; IF fontInfo.size=0 THEN { -- must scale widths s: REAL = sizeInMicas/1000.0; -- scaling factor widthX: REF WidthArray = font.widthX; widthY: REF WidthArray = font.widthY; IF widthX=NIL THEN font.fixedWidthX _ Real.RoundI[s*font.fixedWidthX] ELSE FOR c: CHAR IN CHAR DO w: INTEGER = widthX[c]; IF w#0 THEN widthX[c] _ Real.RoundI[s*w] ENDLOOP; IF widthY=NIL THEN font.fixedWidthY _ Real.RoundI[s*font.fixedWidthY] ELSE FOR c: CHAR IN CHAR DO w: INTEGER = widthY[c]; IF w#0 THEN widthY[c] _ Real.RoundI[s*w] ENDLOOP; }; fontList _ List.Cons[font, fontList]; nFonts _ nFonts+1; }; ENDCASE => ERROR; }; -- FontInitProc FontCompare: List.CompareProc = CHECKED { font2: Font _ NARROW[ref2, Font]; WITH ref1 SELECT FROM font1: Font => IF font1.encoding > font2.encoding THEN RETURN [greater] ELSE IF font1.encoding < font2.encoding THEN RETURN [less] ELSE RETURN [equal]; ENDCASE => ERROR; }; -- FontCompare pressFile.GetFonts[FontInitProc]; IF nFonts # 0 THEN { fontList _ List.Sort[fontList, FontCompare]; fonts _ NEW[Fonts[nFonts+1]]; tooManyFontsForFrame _ (nFonts > IPLimits.topFrameSize); WHILE fontList # NIL DO font: Font = NARROW[fontList.first]; fonts[f] _ font; font.fontNumber _ f; fontName _ Rope.Cat["Xerox/PressFonts/", fonts[f].family, "-", fonts[f].faceCode]; ipMaster.SetUpFont[ fontNumber: f, name: fontName, scale: IP.real[fonts[f].sizeInMicas], rotation: IP.real[fonts[f].rotation/60.0], -- minutes to degrees putInFrame: (NOT tooManyFontsForFrame)]; fontList _ fontList.rest; f _ f+1; ENDLOOP; IF tooManyFontsForFrame THEN { ipMaster.MakeVec[nFonts]; ipMaster.AppendInteger[0]; ipMaster.AppendOp[fset]; }; }; fontFile.Close[]; }; -- LoadFonts ipMaster.BeginPreamble[]; LoadFonts[]; ipMaster.EndPreamble[]; IF progressProc # NIL THEN progressProc[preamble, progressData]; pressFile.GetParts[partNumber: 0, pageProc: PageProc, fontDirectoryProc: NIL]; ipMaster.EndMaster[]; pressFile.ClosePressFile[]; IF progressProc # NIL THEN progressProc[document, progressData]; }; -- ConvertPressToInterpress Error: PUBLIC ERROR [errorCode: ErrorCode] = CODE; END. pPressToIPImpl.mesa Last edited by Shore; January 30, 1983 5:25 pm Last edited by Wyatt; April 5, 1983 4:18 pm Change Log Created by Shore; September 16, 1982 3:21 pm Changed by Shore; September 22, 1982 10:33 am Added ProgressProc Changed by Shore; September 26, 1982 2:54 pm converted to new operator interface and added usePriority stuff Changed by Shore; October 4, 1982 9:40 pm use PressFontReader.ListFonts instead of EnumerateFonts and VisitFontProc Changed by Shore; October 14, 1982 4:49 pm changes for Cedar 3.4 (List.Compare stuff) Changed by Shore; November 16, 1982 1:08 pm converted to Cedar.Style and added node formats Changed by Shore; January 30, 1983 1:11 pm fixed bug in SHOWing the null (empty) string and runs of blanks Changed by Wyatt; March 1, 1983 5:05 pm changed CurveFlatten to round coordinates to nearest mica Changed by Wyatt; March 2, 1983 10:55 am added fullInterpress parameter; generate CurveTo's if fullInterpress is true Changed by Wyatt; March 2, 1983 3:42 pm get InterpressFonts.Widths from local file (included in PressIP.df) Changed by Wyatt; March 3, 1983 2:37 pm changed method of comparing font sizes in font directory lookup Changed by Wyatt; March 16, 1983 10:17 am get InterpressFonts.Widths from /Indigo/Interpress/Fonts/InterpressFonts.Widths Changed by Wyatt; April 5, 1983 4:19 pm rewrote much of this module to simplify it Κψ– "Cedar" style˜head1šΟc™Jš.™.Jš+™+unitšΟk ˜ Jšœžœ/˜—š Ÿœžœ žœžœžœžœ˜:Jš žœžœ žœžœžœ˜>—J˜šŸœžœžœ*˜OJš œ žœžœžœžœ˜>Jšœžœžœžœ˜