<> <> <> <> <> <<>> DIRECTORY Basics, Convert, FileNames, GGBasicTypes, GGFromImager, GGModelTypes, GGObjects, GGOutline, GGParseIn, GGSegment, GGSegmentTypes, GGSlice, GGTraj, GGUtility, GGVector, Imager, ImagerBackdoor, ImagerColor, ImagerFont, ImagerFontPrivate, ImagerInterpress, ImagerPath, ImagerPrivate, ImagerRasterPrivate, ImagerState, ImagerTransformation, Interpress, IO, RefText, Rope, ViewerClasses; GGFromImagerImpl: CEDAR PROGRAM IMPORTS Convert, FileNames, GGParseIn, GGObjects, GGOutline, GGSegment, GGSlice, GGTraj, GGUtility, GGVector, Imager, ImagerBackdoor, ImagerFont, ImagerInterpress, ImagerPath, ImagerRasterPrivate, ImagerState, ImagerTransformation, Interpress, IO, RefText, Rope EXPORTS GGFromImager, Imager, ImagerFont = BEGIN BYTE: TYPE ~ Basics.BYTE; ROPE: TYPE ~ Rope.ROPE; Class: TYPE ~ REF ClassRep; ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep; -- export to Imager.ClassRep Context: TYPE ~ Imager.Context; Color: TYPE ~ Imager.Color; ColorOperator: TYPE ~ Imager.ColorOperator; Clipper: TYPE ~ ImagerBackdoor.Clipper; Font: TYPE ~ ImagerFont.Font; PathProc: TYPE ~ ImagerPath.PathProc; PixelArray: TYPE ~ Imager.PixelArray; Point: TYPE ~ GGBasicTypes.Point; Rectangle: TYPE ~ ImagerTransformation.Rectangle; Slice: TYPE ~ GGModelTypes.Slice; State: TYPE ~ REF StateRep; StateRep: PUBLIC TYPE ~ ImagerState.StateRep; Transformation: TYPE ~ ImagerTransformation.Transformation; VEC: TYPE ~ Imager.VEC; Viewer: TYPE ~ ViewerClasses.Viewer; XChar: TYPE ~ ImagerFont.XChar; XStringProc: TYPE ~ ImagerFont.XStringProc; FontImpl: TYPE ~ ImagerFontPrivate.FontImpl; FontImplRep: PUBLIC TYPE ~ ImagerFontPrivate.FontImplRep; -- export to to ImagerFont Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ scene: GGModelTypes.Scene, feedback: Viewer ]; Warning: PUBLIC SIGNAL [context: Context, code: ATOM, message: ROPE] ~ CODE; Create: PROC [feedback: Viewer] RETURNS [Context] ~ { data: Data ~ NEW[DataRep _ [scene: GGObjects.CreateScene[], feedback: feedback]]; state: State ~ NEW[StateRep _ []]; state.T _ ImagerTransformation.Scale[1.0]; -- allocate storage for a transformation and initialize to the identity <> state.color _ Imager.black; RETURN[NEW[Imager.ContextRep _ [class: gargoyleClass, state: state, data: data]]]; }; Capture: PUBLIC PROC [action: PROC [Context], feedback: Viewer _ NIL] RETURNS [GGModelTypes.Scene] ~ { context: Context ~ Create[feedback]; action[context]; WITH context.data SELECT FROM data: Data => RETURN [data.scene]; ENDCASE => ERROR; }; ProcessStateChanges: PUBLIC PROC [context: Context] ~ { state: State ~ context.state; changed: ImagerState.ChangeFlags ~ state.changed; state.changed _ ImagerState.notChanged; IF changed.clipper AND state.clipper # NIL THEN SIGNAL Warning[context, $Clipping, "NotImplemented: Clipping"]; }; RopeFromXStringProc: PROC [string: XStringProc] RETURNS [rope: ROPE _ NIL] ~ { text: REF TEXT _ RefText.ObtainScratch[256]; set: BYTE _ 0; action: PROC [char: XChar] ~ { IF char.set#set THEN { text _ RefText.AppendChar[to: text, from: VAL[255]]; text _ RefText.AppendChar[to: text, from: VAL[set _ char.set]]; }; text _ RefText.AppendChar[to: text, from: VAL[char.code]]; }; text.length _ 0; string[action]; rope _ Rope.FromRefText[text]; RefText.ReleaseScratch[text]; RETURN [rope]; }; UnpackComplexFontName: PROC [fontName: Rope.ROPE] RETURNS [prefix, family, face: Rope.ROPE, fontSize: REAL] = { <> <> DigitProc: IO.BreakProc = { SELECT char FROM IO.TAB, IO.CR, IO.SP => RETURN [break]; '0, '1, '2, '3, '4, '5, '6, '7, '8, '9 => RETURN [break]; ENDCASE => RETURN [other]; }; AlphaProc: IO.BreakProc = { SELECT char FROM IO.TAB, IO.CR, IO.SP => RETURN [break]; IN ['a .. 'z], IN ['A .. 'Z] => RETURN [break]; ENDCASE => RETURN [other]; }; new, sizeRope: Rope.ROPE; prefix _ FileNames.Directory[path: fontName]; -- "xerox/*fonts/" new _ FileNames.GetShortName[fontName]; -- get family "name" face _ FileNames.Tail[new, '-]; -- get face component (MIR, BRR, ...) IF Rope.Equal[face, new] THEN { -- have a name like Helvetica10I OR TERMINAL endOfName: BOOL; nameStream: IO.STREAM _ IO.RIS[new]; family _ IO.GetTokenRope[nameStream, DigitProc].token; -- get the leading alpha characters sizeRope _ IO.GetTokenRope[nameStream, AlphaProc ! IO.EndOfStream, IO.Error => {endOfName _ TRUE; CONTINUE;};].token; -- get any digit characters fontSize _ Convert.RealFromRope[sizeRope]; IF endOfName THEN face _ "" -- because face = new ELSE face _ Rope.Concat["-", GGParseIn.ReadBlankAndWord[nameStream]]; } ELSE { -- have a name like Helvetica-MIR family _ Rope.Substr[base: new, start: 0, len: Rope.SkipTo[s: new, pos: 0, skip: "-"]]; -- throw away "-XXX" face _ SELECT TRUE FROM Rope.Equal[face, "MRR", FALSE] => "", Rope.Equal[face, "BRR", FALSE] => "-B", Rope.Equal[face, "Bold", FALSE] => "-B", Rope.Equal[face, "MIR", FALSE] => "-I", Rope.Equal[face, "Italic", FALSE] => "-I", Rope.Equal[face, "BIR", FALSE] => "-BI", ENDCASE => ERROR; fontSize _ 1.0; }; }; SetSegColor: PROC [context: Context, seg: GGSegmentTypes.Segment] = { <> seg.color _ IF ISTYPE[context.state.color, ImagerColor.ConstantColor] THEN context.state.color ELSE Imager.black; }; OutlineFromPath: PROC[context: Context, path: PathProc, m: Transformation, closed: BOOL] RETURNS [GGModelTypes.Outline] ~ { curOutline: GGModelTypes.Outline _ NIL; curTraj: GGModelTypes.Traj _ NIL; curSeg: GGSegmentTypes.Segment _ NIL; lp: VEC _ [0,0]; firstPoint: VEC _ [0,0]; Finish: PROC ~ { IF curTraj # NIL THEN { IF curSeg # NIL THEN { IF closed THEN { <> IF curSeg.hi = firstPoint THEN { [] _ GGTraj.AddSegment[curTraj, hi, curSeg, lo]; GGTraj.CloseByDistorting[curTraj, hi]; } ELSE { [] _ GGTraj.AddSegment[curTraj, hi, curSeg, lo]; curSeg _ GGSegment.MakeLine[curSeg.hi, firstPoint, NIL]; curSeg.strokeWidth _ GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ]; SetSegColor[context, curSeg]; GGTraj.CloseWithSegment[curTraj, curSeg, lo]; }; } ELSE [] _ GGTraj.AddSegment[curTraj, hi, curSeg, lo]; } ELSE { -- unlikely but legal case: Traj with a single point, no segment [] _ GGTraj.AddSegment[curTraj, lo, GGSegment.MakeLine[[lp.x, lp.y], [lp.x, lp.y], NIL], lo]; }; curSeg _ NIL; IF curOutline = NIL THEN curOutline _ GGOutline.CreateOutline[curTraj] ELSE curOutline _ GGOutline.AddHole[curOutline, curTraj]; curTraj _ NIL; }; }; Move: PROC [p: VEC] ~ { Finish[]; curTraj _ GGTraj.CreateTraj[[p.x, p.y]]; firstPoint _ lp _ p; }; Line: PROC [p1: VEC] ~ { IF curSeg # NIL THEN [] _ GGTraj.AddSegment[curTraj, hi, curSeg, lo]; curSeg _ GGSegment.MakeLine[[lp.x, lp.y], [p1.x, p1.y], NIL]; curSeg.strokeWidth _ GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ]; <> SetSegColor[context, curSeg]; lp _ p1; }; Curve: PROC [p1, p2, p3: VEC] ~ { IF curSeg # NIL THEN [] _ GGTraj.AddSegment[curTraj, hi, curSeg, lo]; curSeg _ GGSegment.MakeBezier[[lp.x, lp.y], [p1.x, p1.y], [p2.x, p2.y], [p3.x, p3.y], NIL]; curSeg.strokeWidth _ GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ]; <> SetSegColor[context, curSeg]; lp _ p3; }; Conic: PROC [p1, p2: VEC, r: REAL] ~ { IF curSeg # NIL THEN [] _ GGTraj.AddSegment[curTraj, hi, curSeg, lo]; curSeg _ GGSegment.MakeConic[[lp.x, lp.y], [p1.x, p1.y], [p2.x, p2.y], r, NIL]; curSeg.strokeWidth _ GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ]; <> SetSegColor[context, curSeg]; lp _ p2; }; Arc: PROC [p1, p2: VEC] ~ { IF curSeg # NIL THEN [] _ GGTraj.AddSegment[curTraj, hi, curSeg, lo]; curSeg _ GGSegment.MakeArc[[lp.x, lp.y], [p1.x, p1.y], [p2.x, p2.y], NIL]; curSeg.strokeWidth _ GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ]; <> SetSegColor[context, curSeg]; lp _ p2; }; ImagerPath.Transform[path, m, Move, Line, Curve, Conic, Arc]; Finish[]; RETURN [curOutline]; }; MyShow: PROC[context: Context, string: XStringProc, xrel: BOOL] ~ { OPEN ImagerTransformation; textSlice: GGModelTypes.Slice; data: Data _ NARROW[context.data]; font: ImagerFont.Font _ context.class.GetFont[context]; rope: ROPE _ RopeFromXStringProc[string]; escapement: VEC _ ImagerFont.RopeWidth[font, rope]; IF context.state.np.noImage=0 THEN { color: Imager.Color _ context.class.GetColor[context]; currentT: Transformation _ context.class.GetT[context]; currentPoint: Point _ context.class.GetCP[context, FALSE]; charToClientScale: VEC _ Factor[font.charToClient].s; totalTransform: Transformation; fontSize: REAL _ 1.0; amplifySpace: REAL; correctMeasureX: REAL; prefix, family, face, fontName, problem: Rope.ROPE; <> <> <> amplifySpace _ ImagerBackdoor.GetReal[context, $amplifySpace]; correctMeasureX _ ImagerBackdoor.GetReal[context, $correctMX]; [prefix, family, face, fontSize] _ UnpackComplexFontName[font.name]; totalTransform _ Cat[Scale[fontSize], font.charToClient, Translate[currentPoint], currentT]; [fontName, ----, ----, problem] _ GGUtility.FontDataFromUserData[prefix, family, face, 1.0, fontSize]; IF problem#NIL THEN ERROR; textSlice _ GGSlice.MakeTextSlice[rope, color, amplifySpace]; [] _ GGSlice.SetTextFont[slice: textSlice, prefix: prefix, family: family, face: face, fontName: fontName, scale: 1.0, fontScale: fontSize, transform: totalTransform, feedback: NIL]; GGObjects.AddSlice[data.scene, textSlice, -1]; }; ImagerState.StateSetXYRel[context, escapement]; }; MyMaskFill: PROC[context: Context, path: PathProc, oddWrap: BOOL] ~ { data: Data ~ NARROW[context.data]; state: State ~ context.state; IF state.changed#ImagerState.notChanged THEN ProcessStateChanges[context]; IF oddWrap THEN SIGNAL Warning[context, $ParityFill, "NotImplemented: ParityFill"]; IF context.state.np.noImage=0 THEN --CHECKED-- { outline: GGModelTypes.Outline _ OutlineFromPath[context, path, state.T, TRUE]; outline.class.setFillColor[outline, state.color]; GGObjects.AddOutline[data.scene, outline, -1]; }; }; MyMaskStroke: PROC[context: Context, path: PathProc, closed: BOOL] ~ { outline: GGModelTypes.Outline; data: Data ~ NARROW[context.data]; state: State ~ context.state; IF state.changed#ImagerState.notChanged THEN ProcessStateChanges[context]; IF context.state.np.noImage=0 THEN { outline _ OutlineFromPath[context, path, state.T, closed]; <> outline.class.setFillColor[outline, NIL]; -- no fill color GGObjects.AddOutline[data.scene, outline, -1]; }; }; MyMaskDashedStroke: PROC[context: Context, path: PathProc, patternLen: NAT, pattern: PROC [NAT] RETURNS [REAL], offset, length: REAL] ~ { <> MyMaskStroke[context, path, FALSE]; }; MyMaskRectangle: PROC[context: Context, r: Rectangle] ~ { path: PathProc ~ { moveTo[[r.x, r.y]]; lineTo[[r.x+r.w, r.y]]; lineTo[[r.x+r.w, r.y+r.h]]; lineTo[[r.x, r.y+r.h]] }; MyMaskFill[context, path, FALSE]; }; MyMaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ~ { MyMaskRectangle[context, [x, y, w, h]]; }; MyMaskVector: PROC[context: Context, p1, p2: VEC] ~ { path: PathProc ~ {moveTo[p1]; lineTo[p2]}; MyMaskStroke[context, path, FALSE]; }; MyMaskPixel: PROC[context: Context, pa: PixelArray] ~ { DoMyMaskPixel: PROC [dc: Imager.Context] = { Imager.MaskPixel[dc, pa]; }; data: Data _ NARROW[context.data]; ipSlice: Slice; currentColor: Color; currentT: ImagerTransformation.Transformation; currentColor _ context.state.color; currentT _ ImagerTransformation.Copy[context.state.T]; ipSlice _ GGSlice.MakeIPSliceFromMaskPixel[pa, currentColor, NIL, currentT]; GGObjects.AddSlice[data.scene, ipSlice, -1]; }; MyMaskBits: PROC[context: Context, base: LONG POINTER, wordsPerLine: NAT, sMin, fMin, sSize, fSize: NAT, tx, ty: INTEGER] ~ { DoMyMaskBits: PROC [dc: Imager.Context] = { Imager.MaskBits[dc, base, wordsPerLine, sMin, fMin, sSize, fSize, tx, ty]; }; masterStream, outStream: IO.STREAM; masterRope: Rope.ROPE; data: Data _ NARROW[context.data]; ipRef: ImagerInterpress.Ref; ipMaster: Interpress.Master; ipSlice: Slice; SIGNAL Warning[context, $MaskBits, "NotImplemented: MaskBits"]; outStream _ IO.ROS[]; ipRef _ ImagerInterpress.CreateFromStream[outStream, "Interpress/Xerox/3.0 "]; ImagerInterpress.DoPage[ipRef, DoMyMaskBits]; ImagerInterpress.Finish[ipRef]; masterRope _ IO.RopeFromROS[outStream]; masterStream _ IO.RIS[masterRope]; ipMaster _ Interpress.FromStream[masterStream, NIL]; <> GGObjects.AddSlice[data.scene, ipSlice, -1]; }; MyDrawBits: PROC[context: Context, base: LONG POINTER, wordsPerLine: NAT, sMin, fMin, sSize, fSize: NAT, tx, ty: INTEGER] ~ { DoMyDrawBits: PROC [dc: Imager.Context] = { Imager.MaskBits[dc, base, wordsPerLine, sMin, fMin, sSize, fSize, tx, ty]; }; masterStream, outStream: IO.STREAM; masterRope: Rope.ROPE; data: Data _ NARROW[context.data]; ipRef: ImagerInterpress.Ref; ipMaster: Interpress.Master; ipSlice: Slice; SIGNAL Warning[context, $DrawBits, "NotImplemented: DrawBits"]; outStream _ IO.ROS[]; ipRef _ ImagerInterpress.CreateFromStream[outStream, "Interpress/Xerox/3.0 "]; ImagerInterpress.DoPage[ipRef, DoMyDrawBits]; ImagerInterpress.Finish[ipRef]; masterRope _ IO.RopeFromROS[outStream]; masterStream _ IO.RIS[masterRope]; ipMaster _ Interpress.FromStream[masterStream, NIL]; <> GGObjects.AddSlice[data.scene, ipSlice, -1]; }; MyGetBounds: PROC[context: Context] RETURNS[Rectangle] ~ { ERROR Imager.Error[[$NotImplemented, "NotImplemented: GetBounds"]] }; gargoyleClass: Class ~ NEW[ClassRep _ [ type: $Gargoyle, DoSave: ImagerState.StateDoSave, SetInt: ImagerState.StateSetInt, SetReal: ImagerState.StateSetReal, SetT: ImagerState.StateSetT, SetFont: ImagerState.StateSetFont, SetColor: ImagerState.StateSetColor, SetClipper: ImagerState.StateSetClipper, GetInt: ImagerState.StateGetInt, GetReal: ImagerState.StateGetReal, GetT: ImagerState.StateGetT, GetFont: ImagerState.StateGetFont, GetColor: ImagerState.StateGetColor, GetClipper: ImagerState.StateGetClipper, ConcatT: ImagerState.StateConcatT, Scale2T: ImagerState.StateScale2T, RotateT: ImagerState.StateRotateT, TranslateT: ImagerState.StateTranslateT, Move: ImagerState.StateMove, SetXY: ImagerState.StateSetXY, SetXYRel: ImagerState.StateSetXYRel, Show: MyShow, ShowText: ImagerRasterPrivate.RasterShowText, StartUnderline: ImagerState.StateStartUnderline, MaskUnderline: ImagerState.StateMaskUnderline, CorrectMask: ImagerState.StateCorrectMask, CorrectSpace: ImagerState.StateCorrectSpace, Space: ImagerState.StateSpace, SetCorrectMeasure: ImagerState.StateSetCorrectMeasure, SetCorrectTolerance: ImagerState.StateSetCorrectTolerance, Correct: ImagerState.StateCorrect, DontCorrect: ImagerState.StateDontCorrect, SetGray: ImagerState.StateSetGray, SetSampledColor: ImagerState.StateSetSampledColor, SetSampledBlack: ImagerState.StateSetSampledBlack, MaskFill: MyMaskFill, MaskStroke: MyMaskStroke, MaskDashedStroke: MyMaskDashedStroke, MaskRectangle: MyMaskRectangle, MaskRectangleI: MyMaskRectangleI, MaskVector: MyMaskVector, MaskPixel: MyMaskPixel, MaskBits: MyMaskBits, DrawBits: MyDrawBits, Clip: ImagerState.StateClip, ClipRectangle: ImagerState.StateClipRectangle, ClipRectangleI: ImagerState.StateClipRectangleI, GetCP: ImagerState.StateGetCP, GetBoundingRectangle: MyGetBounds, propList: NIL ]]; END.