<> <> <> DIRECTORY CGArea, CGClipper, CGContext, CGDevice, CGReducer, Graphics USING [Box, SetColor], IPBasic USING [Integer], IPCubic USING [Flat, Split], IPErrors USING [AppearanceWarning], IPGeometry USING [MapOutline, MapTrajectory], IPImager USING [Imager, Vars], IPImagerOps USING [GetCP, SetXY, Trans], IPImagerBasic USING [Bezier, ConstantColor, Outline, Pair, PixelArray, StrokeEnds, Trajectory, Transformation], IPOutput USING [Show], IPScan USING [PopPath, PushPath, ScanConvert], IPState USING [State, StateRep], IPStroke USING [GenerateStroke], IPTransform USING [Transform, TransformVec]; IPMaskImpl: CEDAR PROGRAM IMPORTS CGArea, CGClipper, CGReducer, Graphics, IPCubic, IPErrors, IPGeometry, IPImagerOps, IPOutput, IPScan, IPStroke, IPTransform EXPORTS IPImagerOps, IPBasic = BEGIN OPEN IPImagerBasic, IPBasic; State: TYPE = IPState.State; StateRep: PUBLIC TYPE = IPState.StateRep; -- export to IPBasic Imager: TYPE = IPImager.Imager; Vars: TYPE = IPImager.Vars; SetColor: PROC[imager: Imager] = INLINE { icolor: ConstantColor = NARROW[imager.vars.color]; Graphics.SetColor[imager.context, [r: icolor.r/256, g: icolor.g/256, b: icolor.b/256]]; }; useScanConverter: BOOL _ TRUE; CGMaskFill: PROC[imager: Imager, o: Outline] = { vars: Vars = imager.vars; T: Transformation = vars.T; d: CGContext.Ref = NARROW[imager.context.data]; reducer: CGReducer.Ref = d.reducer; area: CGArea.Ref = d.area; device: CGDevice.Ref = d.device; lp: Pair; started: BOOL _ FALSE; Move: PROC[v: Pair] = { IF started THEN Close[] ELSE started _ TRUE; Line[v]; }; Line: PROC[v: Pair] = { IF NOT started THEN ERROR; CGReducer.Vertex[reducer, [v.x, v.y]]; lp _ v; }; Curve: PROC[v1, v2, v3: Pair] = { eps: REAL = 1.5; maxdepth: NAT = 10; Divide: PROC[b: Bezier, depth: NAT _ 0] = { IF depth>=maxdepth OR IPCubic.Flat[b, eps] THEN Line[b.b3] ELSE { b1, b2: Bezier; [b1, b2] _ IPCubic.Split[b]; Divide[b1, depth+1]; Divide[b2, depth+1] }; }; Divide[[lp, v1, v2, v3]]; }; Close: PROC = { CGReducer.Close[reducer] }; SetColor[imager]; CGClipper.Load[d.clipper, reducer]; IPGeometry.MapOutline[o, vars.T, Move, Line, Curve]; IF started THEN Close[]; CGReducer.Generate[reducer, area]; IF NOT CGArea.Empty[area] THEN device.Show[device, area, d.src, NIL]; }; IPMaskFill: PROC[imager: Imager, o: Outline] = { vars: Vars = imager.vars; T: Transformation = vars.T; Gen: PROC[move: PROC[Pair], line: PROC[Pair], curve: PROC[Pair, Pair, Pair]] = { IPGeometry.MapOutline[o, T, move, line, curve]; }; Out: PROC[rect: PROC[x, y, w, h: INTEGER]] = { IPScan.ScanConvert[imager.path, rect]; }; IPScan.PushPath[imager.path, Gen]; imager.output.Show[vars.color, Out]; IPScan.PopPath[imager.path]; }; MaskFill: PUBLIC PROC[self: State, o: Outline] = { imager: Imager = self.imager; vars: Vars = imager.vars; IF vars.np.noImage=0 THEN { IF useScanConverter THEN IPMaskFill[imager, o] ELSE CGMaskFill[imager, o]; }; }; MaskRectangle: PUBLIC PROC[self: State, x, y, w, h: REAL] = { imager: Imager = self.imager; vars: Vars = imager.vars; IF vars.np.noImage=0 THEN { -- imager.procs.MaskRectangle[imager, x, y, w, h]; -- T: Transformation = vars.T; SetColor[imager]; IF T.code<10 THEN { d: CGContext.Ref = NARROW[imager.context.data]; box: Graphics.Box; p: Pair = IPTransform.Transform[T, [x, y]]; v: Pair = IPTransform.TransformVec[T, [w, h]]; IF v.x<0 THEN { box.xmin _ p.x+v.x; box.xmax _ p.x } ELSE { box.xmin _ p.x; box.xmax _ p.x+v.x }; IF v.y<0 THEN { box.ymin _ p.y+v.y; box.ymax _ p.y } ELSE { box.ymin _ p.y; box.ymax _ p.y+v.y }; CGClipper.GenerateBox[d.clipper, box, d.reducer, d.area]; IF NOT CGArea.Empty[d.area] THEN d.device.Show[d.device, d.area, d.src, NIL]; } ELSE { Gen: PROC[move: PROC[Pair], line: PROC[Pair], curve: PROC[Pair, Pair, Pair]] = { move[IPTransform.Transform[T, [x, y]]]; line[IPTransform.Transform[T, [x+w, y]]]; line[IPTransform.Transform[T, [x+w, y+h]]]; line[IPTransform.Transform[T, [x, y+h]]]; }; Out: PROC[rect: PROC[x, y, w, h: INTEGER]] = { IPScan.ScanConvert[imager.path, rect]; }; IPScan.PushPath[imager.path, Gen]; imager.output.Show[vars.color, Out]; IPScan.PopPath[imager.path]; }; }; }; GenStroke: PROC[imager: Imager, gen: PROC[move: PROC[Pair], line: PROC[Pair], curve: PROC[Pair, Pair, Pair]], closed: BOOL _ FALSE] = { vars: Vars = imager.vars; ends: StrokeEnds = (SELECT vars.np.strokeEnd FROM 0 => square, 1 => butt, 2 => round, ENDCASE => square); d: CGContext.Ref = NARROW[imager.context.data]; reducer: CGReducer.Ref = d.reducer; area: CGArea.Ref = d.area; device: CGDevice.Ref = d.device; started: BOOL _ FALSE; Move: PROC[v: Pair] = { IF started THEN Close[] ELSE started _ TRUE; Line[v]; }; Line: PROC[v: Pair] = { IF NOT started THEN ERROR; CGReducer.Vertex[reducer, [v.x, v.y]]; }; Curve: PROC[v1, v2, v3: Pair] = { ERROR; }; Close: PROC = { CGReducer.Close[reducer] }; SetColor[imager]; CGClipper.Load[d.clipper, reducer]; IPStroke.GenerateStroke[gen, vars.T, vars.np.strokeWidth, closed, ends, Move, Line, Curve]; IF started THEN Close[]; CGReducer.Generate[reducer, area]; IF NOT CGArea.Empty[area] THEN device.Show[device, area, d.src, NIL]; }; MaskStroke: PUBLIC PROC[self: State, t: Trajectory, closed: BOOL _ FALSE] = { imager: Imager = self.imager; vars: Vars = imager.vars; IF vars.np.noImage=0 THEN { Gen: PROC[move: PROC[Pair], line: PROC[Pair], curve: PROC[Pair, Pair, Pair]] = { IPGeometry.MapTrajectory[t, NIL, move, line, curve] }; GenStroke[imager, Gen, closed]; }; }; MaskVector: PUBLIC PROC[self: State, p1, p2: Pair] = { imager: Imager = self.imager; vars: Vars = imager.vars; IF vars.np.noImage=0 THEN { Gen: PROC[move: PROC[Pair], line: PROC[Pair], curve: PROC[Pair, Pair, Pair]] = { move[p1]; line[p2] }; GenStroke[imager, Gen]; }; }; MaskTrapezoidX: PUBLIC PROC[self: State, x1, y1, x2, x3, y3, x4: REAL] = { imager: Imager = self.imager; vars: Vars = imager.vars; IF vars.np.noImage=0 THEN SIGNAL IPErrors.AppearanceWarning[Unimplemented]; }; MaskTrapezoidY: PUBLIC PROC[self: State, x1, y1, y2, x3, y3, y4: REAL] = { imager: Imager = self.imager; vars: Vars = imager.vars; IF vars.np.noImage=0 THEN SIGNAL IPErrors.AppearanceWarning[Unimplemented]; }; StartUnderline: PUBLIC PROC[self: State] = { imager: Imager = self.imager; vars: Vars = imager.vars; p: Pair = IPImagerOps.GetCP[self]; vars.np.underlineStart _ p.x; }; MaskUnderline: PUBLIC PROC[self: State, dy, h: REAL] = { imager: Imager = self.imager; vars: Vars = imager.vars; IF vars.np.noImage=0 THEN { cpx: REAL = vars.p.cpx; cpy: REAL = vars.p.cpy; -- save cp and translation tc: REAL = vars.T.c; tf: REAL = vars.T.f; p: Pair = IPImagerOps.GetCP[self]; -- current position, master coordinates x: REAL = vars.np.underlineStart; -- x of rectangle y: REAL = p.y-dy-h; -- y of rectangle w: REAL = p.x-x; -- width of rectangle IPImagerOps.SetXY[self, [x, y]]; IPImagerOps.Trans[self]; MaskRectangle[self, 0, 0, w, h]; vars.p.cpx _ cpx; vars.p.cpy _ cpy; -- restore cp and translation vars.T.c _ tc; vars.T.f _ tf; }; }; MaskPixel: PUBLIC PROC[self: State, pa: PixelArray] = { imager: Imager = self.imager; vars: Vars = imager.vars; IF vars.np.noImage=0 THEN SIGNAL IPErrors.AppearanceWarning[Unimplemented]; }; END.