DIRECTORY Atom USING [PropList], Font USING [FONT], ImagerBasic USING [ColorRep, Pair, PathMapType, PixelArray], ImagerTransform USING [Transformation, TransformationRec], Rope USING [ROPE]; Imager: CEDAR DEFINITIONS ~ BEGIN Context: TYPE ~ REF ContextRep; ContextRep: TYPE ~ RECORD[ class: Class, -- procedures for the context class state: REF, -- state of the imager variables, if available data: REF, -- instance data, type depends on the class propList: Atom.PropList -- a property list ]; Create: PROC[deviceType: ATOM, data: REF _ NIL] RETURNS [Context]; Error: ERROR[errorCode: ErrorCode]; ErrorCode: TYPE ~ ATOM; DoSave: PROC[context: Context, body: PROC]; DoSaveAll: PROC[context: Context, body: PROC]; SetPriorityImportant: PROC[context: Context, priorityImportant: BOOL]; PutProp: PROC[context: Context, key: REF, value: REF]; GetProp: PROC[context: Context, key: REF] RETURNS[value: REF]; RemProp: PROC[context: Context, key: REF]; Transformation: TYPE ~ ImagerTransform.Transformation; Matrix: TYPE ~ ImagerTransform.TransformationRec; MakeT: PROC[Matrix] RETURNS[Transformation]; OpenT: PROC[Transformation] RETURNS[Matrix]; Scale: PROC[s: REAL] RETURNS[Transformation]; Scale2: PROC[sx, sy: REAL] RETURNS[Transformation]; Rotate: PROC[a: REAL] RETURNS[Transformation]; Translate: PROC[x, y: REAL] RETURNS[Transformation]; Concat: PROC[m, n: Transformation] RETURNS[Transformation]; Invert: PROC[m: Transformation] RETURNS[Transformation]; Transform: PROC[m: Transformation, p: Pair] RETURNS[Pair]; TransformVec: PROC[m: Transformation, p: Pair] RETURNS[Pair]; InverseTransform: PROC[m: Transformation, p: Pair] RETURNS[Pair]; InverseTransformVec: PROC[m: Transformation, p: Pair] RETURNS[Pair]; ConcatT: PROC[context: Context, m: Transformation]; ScaleT: PROC[context: Context, s: REAL]; micasToMeters: REAL ~ 0.00001; inchesToMeters: REAL ~ micasToMeters*2540; pointsToMeters: REAL ~ inchesToMeters/72.27; Scale2T: PROC[context: Context, sx, sy: REAL]; RotateT: PROC[context: Context, a: REAL]; TranslateT: PROC[context: Context, x, y: REAL]; Move: PROC[context: Context]; Trans: PROC[context: Context]; Pair: TYPE ~ ImagerBasic.Pair; -- RECORD[x, y: REAL] Trajectory: TYPE ~ REF TrajectoryRep; TrajectoryRep: TYPE ~ RECORD[ prev: Trajectory, -- the preceding trajectory lp: Pair, -- the last point variant: SELECT tag: * FROM move => [], -- begin new trajectory at lp line => [], -- straight line, endpoints [prev.lp, lp] curve => [p1, p2: Pair], -- cubic curve, Bezier control points [prev.lp, p1, p2, lp] conic => [p1: Pair, r: REAL], -- conic curve, control points [prev.lp, p1, lp] ENDCASE ]; TrajectoryList: TYPE ~ LIST OF Trajectory; LastPoint: PROC[t: Trajectory] RETURNS[x, y: REAL]; LastPointP: PROC[t: Trajectory] RETURNS[Pair]; MoveTo: PROC[x, y: REAL] RETURNS[Trajectory]; MoveToP: PROC[p: Pair] RETURNS[Trajectory]; LineTo: PROC[t: Trajectory, x, y: REAL] RETURNS[Trajectory]; LineToP: PROC[t: Trajectory, p: Pair] RETURNS[Trajectory]; LineToX: PROC[t: Trajectory, x: REAL] RETURNS[Trajectory]; LineToY: PROC[t: Trajectory, y: REAL] RETURNS[Trajectory]; CurveTo: PROC[t: Trajectory, x1, y1, x2, y2, x3, y3: REAL] RETURNS[Trajectory]; CurveToP: PROC[t: Trajectory, p1, p2, p3: Pair] RETURNS[Trajectory]; ConicTo: PROC[t: Trajectory, x1, y1, x2, y2: REAL, r: REAL] RETURNS[Trajectory]; ConicToP: PROC[t: Trajectory, p1, p2: Pair, r: REAL] RETURNS[Trajectory]; ArcTo: PROC[t: Trajectory, x1, y1, x2, y2: REAL] RETURNS[Trajectory]; ArcToP: PROC[t: Trajectory, p1, p2: Pair] RETURNS[Trajectory]; PathProc: TYPE ~ ImagerBasic.PathMapType; MapTrajectory: PathProc; -- for a Trajectory MapTrajectoryList: PathProc; -- for a TrajectoryList MaskFill: PROC[context: Context, outline: REF]; MaskFillPath: PROC[context: Context, pathProc: PathProc, pathData: REF _ NIL]; SetStrokeWidth: PROC[context: Context, strokeWidth: REAL]; StrokeEnd: TYPE ~ { square, -- Square off the end after extending the stroke by half its width butt, -- Square off the end flush with the endpoint round -- Round the end with a semicircular cap }; SetStrokeEnd: PROC[context: Context, strokeEnd: StrokeEnd]; MaskStroke: PROC[context: Context, stroke: REF]; MaskStrokeClosed: PROC[context: Context, stroke: REF]; MaskStrokePath: PROC[context: Context, pathProc: PathProc, pathData: REF _ NIL]; MaskStrokeClosedPath: PROC[context: Context, pathProc: PathProc, pathData: REF _ NIL]; MaskRectangle: PROC[context: Context, x, y, w, h: REAL]; MaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ~ INLINE { context.class.MaskRectangleI[context, x, y, w, h] }; Box: TYPE ~ RECORD[xmin, ymin, xmax, ymax: REAL]; MaskBox: PROC[context: Context, box: Box]; MaskVector: PROC[context: Context, x1, y1, x2, y2: REAL]; MaskVectorI: PROC[context: Context, x1, y1, x2, y2: INTEGER] ~ INLINE { context.class.MaskVectorI[context, x1, y1, x2, y2] }; MaskVectorP: PROC[context: Context, p1, p2: Pair]; SetNoImage: PROC[context: Context, noImage: BOOL]; SetXY: PROC[context: Context, x, y: REAL]; SetXYI: PROC[context: Context, x, y: INTEGER] ~ INLINE { context.class.SetXYI[context, x, y] }; SetXYP: PROC[context: Context, p: Pair]; SetXYRel: PROC[context: Context, x, y: REAL]; SetXYRelI: PROC[context: Context, x, y: INTEGER] ~ INLINE { context.class.SetXYRelI[context, x, y] }; SetXYRelP: PROC[context: Context, p: Pair]; SetXRel: PROC[context: Context, x: REAL]; SetXRelI: PROC[context: Context, x: INTEGER] ~ INLINE { context.class.SetXYRelI[context, x, 0] }; SetYRel: PROC[context: Context, y: REAL]; SetYRelI: PROC[context: Context, y: INTEGER] ~ INLINE { context.class.SetXYRelI[context, 0, y] }; FONT: TYPE ~ Font.FONT; ROPE: TYPE ~ Rope.ROPE; FindFont: PROC[name: ROPE] RETURNS[FONT]; ModifyFont: PROC[font: FONT, m: Transformation] RETURNS[FONT]; MakeFont: PROC[name: ROPE, size: REAL] RETURNS[FONT]; SetFont: PROC[context: Context, font: FONT]; ShowRope: PROC[context: Context, rope: ROPE, start: INT _ 0, len: INT _ INT.LAST]; ShowText: PROC[context: Context, text: REF READONLY TEXT, start: NAT _ 0, len: NAT _ NAT.LAST]; ShowChar: PROC[context: Context, char: CHAR]; SetAmplifySpace: PROC[context: Context, amplifySpace: REAL]; StartUnderline: PROC[context: Context]; MaskUnderline: PROC[context: Context, dy, h: REAL]; MaskUnderlineI: PROC[context: Context, dy, h: INTEGER] ~ INLINE { context.class.MaskUnderlineI[context, dy, h] }; CorrectMask: PROC[context: Context]; CorrectSpace: PROC[context: Context, x, y: REAL]; CorrectSpaceP: PROC[context: Context, p: Pair]; Correct: PROC[context: Context, body: PROC]; SetCorrectMeasure: PROC[context: Context, x, y: REAL]; SetCorrectMeasureP: PROC[context: Context, p: Pair]; SetCorrectTolerance: PROC[context: Context, x, y: REAL]; SetCorrectToleranceP: PROC[context: Context, p: Pair]; SetCorrectShrink: PROC[context: Context, correctShrink: REAL]; Space: PROC[context: Context, x: REAL]; SpaceI: PROC[context: Context, x: INTEGER] ~ INLINE { context.class.SpaceI[context, x] }; PixelArray: TYPE ~ ImagerBasic.PixelArray; MakePixelArrayFromBits: PROC[ bitPointer: LONG POINTER TO PACKED ARRAY [0..0) OF [0..1], bitsPerLine, samplesPerLine, numberOfLines: NAT ] RETURNS [PixelArray]; MaskPixel: PROC[context: Context, pa: PixelArray]; ConstantColor: TYPE ~ REF ImagerBasic.ColorRep[constant]; MakeGray: PROC[f: REAL] RETURNS[ConstantColor]; black: ConstantColor; -- MakeGray[1] white: ConstantColor; -- MakeGray[0] Color: TYPE ~ REF ImagerBasic.ColorRep; SetSampledColor: PROC[context: Context, pa: PixelArray, pixelT: Transformation, colorOperator: ATOM _ $Intensity]; SetSampledBlack: PROC[context: Context, pa: PixelArray, pixelT: Transformation, transparent: BOOLEAN _ FALSE]; SetColor: PROC[context: Context, color: Color]; SetGray: PROC[context: Context, f: REAL]; ClipOutline: PROC[context: Context, outline: REF]; ClipOutlinePath: PROC[context: Context, pathProc: PathProc, pathData: REF _ NIL]; ExcludeOutline: PROC[context: Context, outline: REF]; ExcludeOutlinePath: PROC[context: Context, pathProc: PathProc, pathData: REF _ NIL]; ClipRectangle: PROC[context: Context, x, y, w, h: REAL]; ClipRectangleI: PROC[context: Context, x, y, w, h: INTEGER]; ExcludeRectangle: PROC[context: Context, x, y, w, h: REAL]; ExcludeRectangleI: PROC[context: Context, x, y, w, h: INTEGER]; Class: TYPE ~ REF ClassRep; ClassRep: TYPE ~ RECORD[ type: ATOM, DoSave: PROC[context: Context, body: PROC] _, DoSaveAll: PROC[context: Context, body: PROC] _, SetPriorityImportant: PROC[context: Context, priorityImportant: BOOL] _, SetFont: PROC[context: Context, font: FONT] _, SetColor: PROC[context: Context, color: Color] _, SetNoImage: PROC[context: Context, noImage: BOOL] _, SetStrokeWidth: PROC[context: Context, strokeWidth: REAL] _, SetStrokeEnd: PROC[context: Context, strokeEnd: StrokeEnd] _, SetAmplifySpace: PROC[context: Context, amplifySpace: REAL] _, SetCorrectShrink: PROC[context: Context, correctShrink: REAL] _, ConcatT: PROC[context: Context, m: Transformation] _, ScaleT: PROC[context: Context, s: REAL] _, Scale2T: PROC[context: Context, sx, sy: REAL] _, RotateT: PROC[context: Context, a: REAL] _, TranslateT: PROC[context: Context, x, y: REAL] _, Move: PROC[context: Context] _, Trans: PROC[context: Context] _, ShowRope: PROC[context: Context, rope: ROPE, start, len: INT] _, ShowText: PROC[context: Context, text: REF READONLY TEXT, start, len: NAT] _, ShowChar: PROC[context: Context, char: CHAR] _, SetXY: PROC[context: Context, x, y: REAL] _, SetXYI: PROC[context: Context, x, y: INTEGER] _, SetXYRel: PROC[context: Context, x, y: REAL] _, SetXYRelI: PROC[context: Context, x, y: INTEGER] _, SetSampledColor: PROC[context: Context, pa: PixelArray, pixelT: Transformation, colorOperator: ATOM] _, SetSampledBlack: PROC[context: Context, pa: PixelArray, pixelT: Transformation, transparent: BOOL] _, SetGray: PROC[context: Context, f: REAL] _, MaskFill: PROC[context: Context, pathProc: PathProc, pathData: REF] _, MaskStroke: PROC[context: Context, pathProc: PathProc, pathData: REF] _, MaskStrokeClosed: PROC[context: Context, pathProc: PathProc, pathData: REF] _, MaskVector: PROC[context: Context, x1, y1, x2, y2: REAL] _, MaskVectorI: PROC[context: Context, x1, y1, x2, y2: INTEGER] _, MaskRectangle: PROC[context: Context, x, y, w, h: REAL] _, MaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER] _, StartUnderline: PROC[context: Context] _, MaskUnderline: PROC[context: Context, dy, h: REAL] _, MaskUnderlineI: PROC[context: Context, dy, h: INTEGER] _, MaskPixel: PROC[context: Context, pa: PixelArray] _, ClipOutline: PROC[context: Context, pathProc: PathProc, pathData: REF] _, ExcludeOutline: PROC[context: Context, pathProc: PathProc, pathData: REF] _, ClipRectangle: PROC[context: Context, x, y, w, h: REAL] _, ClipRectangleI: PROC[context: Context, x, y, w, h: INTEGER] _, ExcludeRectangle: PROC[context: Context, x, y, w, h: REAL] _, ExcludeRectangleI: PROC[context: Context, x, y, w, h: INTEGER] _, CorrectMask: PROC[context: Context] _, CorrectSpace: PROC[context: Context, x, y: REAL] _, Correct: PROC[context: Context, body: PROC] _, SetCorrectMeasure: PROC[context: Context, x, y: REAL] _, SetCorrectTolerance: PROC[context: Context, x, y: REAL] _, Space: PROC[context: Context, x: REAL] _, SpaceI: PROC[context: Context, x: INTEGER] _ ]; END. 4pImager.mesa -- Copyright (C) 1984 Xerox Corporation. All rights reserved. Michael Plass, February 20, 1984 9:15:15 am PST Doug Wyatt, July 2, 1984 1:24:34 pm PDT The Imager provides a rich set of facilities for creating two-dimensional images on a variety of devices; images can be specified in a way that is independent of any particular imaging device. Introduction The imaging model Prose. Contexts For making a new context. The data field is optional; its type is dependent on the deviceType. Errors $Bug -- detected an internal inconsistency $Unimplemented -- operation not provided for this context $NotYetImplemented -- part of the Imager implementation is incomplete $InvalidState -- context.state is NIL or has wrong type $ZeroDivideInCorrectSpace -- CorrectSpace calculation tried to divide by zero $UnableToProperlyAdjustMaskPositions -- Correct failed to achieve target measure $UnknownSpecialColor -- unrecognized atom for a special Color $UnknownColorModel -- unrecognized colorOperator for a sampled color $MustBeRopeOrRefText -- characters argument is not ROPE or REF TEXT $UnimplementedSpecialOp -- unrecognized op for SpecialOp State The state of the imager is contained in two places: the page image, and the imager variables. cpx, cpy: REAL correctMX, correctMY: REAL T: Transformation priorityImportant: BOOL font: FONT color: Color noImage: BOOL strokeWidth: REAL strokeEnd: StrokeEnd underlineStart: REAL amplifySpace: REAL correctShrink: REAL correctTX, correctTY: REAL clipper: Clipper The variables differ in their treatment by the Do-operators below: the non-persistent variables are restored by DoSave; all variables are restored by DoSaveAll. Priority Set the current value of priorityImportant. A change to the image induced by a mask operator is said to be "ordered" if priorityImportant is TRUE, and "unordered" if priorityImportant is FALSE. The rule is that the priority order of all ordered image changes must be preserved; the imager is allowed to alter priority order among unordered changes, or between ordered and unordered changes. Because preserving priority order may require more computation than allowing arbitrary reordering of objects, creators should leave priorityImportant FALSE if possible (this is the default). [[Change default to TRUE?]] Property lists The following procedures provide a property-list mechanism. The key-value association is saved and restored by DoSave and DoSaveAll. Put (key, value) on the context's property list. Get key's value from the context's property list. Remove key from the context's property list. Transformations Creating transformations Applying transformations The current transformation Equivalent to context.ConcatT[Scale[s]]. Some commonly used scale factors. Equivalent to context.ConcatT[Scale2[sx, sy]]. Equivalent to context.ConcatT[Rotate[a]]. Angle a is measured in degrees. Positive angles will rotate subsequent geometrical figures counterclockwise. Equivalent to context.ConcatT[Translate[x, y]] Modify T so that the origin maps to the current position. Modify T so that the origin maps to the rounded current position. The rounding in Trans implies that any coordinates to which T is subsequently applied will be translated by an integral number of grid points. This convention allows often-used instances such as characters to be scan-converted once and then translated at will. Trans is designed together with SetXYRel (see below) to achieve positioning precision, while still letting each instance of a character be scan-converted identically. Mask operators The mask operators are the central focus of the imager, for they determine the shapes of primitive images that are laid down on the image. Mask operators are available to make images of rectangles, line drawings, or filled outlines, and to use a pixel array to specify samples of the mask. When a mask operator is executed, the page image is altered. The operation of a mask operator is controlled in part by its arguments and in part by imager variables:  The current transformation, T, transforms the specified mask shape to determine the coordinates of the mask on the image.  The current color governs the color of the object that will be placed on the image.  If priorityImportant is TRUE, the priority order of objects laid down is preserved.  If noImage is TRUE, mask operators will have no effect on the image, although they will have the proper effect on the imager variables. Shapes are defined geometrically in terms of segments, trajectories, and outlines. A segment is a directed segment of a straight line, cubic curve, or conic section; it has a start point and an end point. A trajectory is a sequence of connected segments; the end point of a segment coincides with the start point ot the next one. A closed trajectory is a trajectory that closes upon itself, that is, the end point of the last segment in the trajectory coincides with the start point of the first segment. An outline is a collection of trajectories; each trajectory in an outline is implicitly closed by a straight-line segment linking the end point of the last segment with the start point of the first segment. Trajectories A Trajectory is an immutable value. MoveTo creates a new trajectory; other operations add a straight or curved segment and return an extended trajectory. Every trajectory has a last point (lp); the lp is the end point of the trajectory's last segment. Return t's lp. Create a new trajectory, containing a single vertex. Its lp is p. Extend t with a straight line segment. The lp of the result is p. LineToX is equivalent to t.LineTo[x, t.lp.y]. LineToY is equivalent to t.LineTo[t.lp.x, y]. Extend t with a cubic curve segment. The lp of the result is p3. Let p0 = t.lp. The curve segment is defined by Bezier control points p0, p1, p2, p3. It starts at p0, tangent to the line joining p0 and p1, and ends at p3, tangent to the line joining p2 and p3. It is bounded by the quadrilateral with vertices p0, p1, p2, p3. Extend t with a segment of a conic section. The lp of the result is p2. Let p0 = t.lp. Let m be the midpoint of the line joining p0 and p2. Let p be the point on the line joining m and p1 such that Length[m, p]/Length[m, p1] = r. The curve segment starts at p0, passes through p, and ends at p2. It is a line if r=0; an ellipse if 0J™1—šŸœœœ˜*J™,—J˜——šœ™™Jšœœ"˜6Jšœœ%˜1J˜JšŸœœ œ˜,JšŸœœœ ˜,J˜JšŸœœœœ˜-JšŸœœ œœ˜3JšŸœœœœ˜.JšŸ œœœœ˜4J˜JšŸœœœ˜;šŸœœœ˜8J˜——™JšŸ œœœ˜:šŸ œœœ˜=J˜—JšŸœœœ˜AšŸœœœ˜DJ™——™šŸœœ&˜3J™—šŸœœœ˜(Jšœ(™(J˜—Jšœœ ˜Jšœœ˜*šœœ˜,J™!J™—šŸœœœ˜.Jšœ.™.J™—šŸœœœ˜)JšœJ™JJšœL™LJ™—šŸ œœœ˜/J™.J™J™—šŸœœ˜Jšœ9™9J™—šŸœœ˜šœA™AInotešœ«™«————šœ™šœ‘™‘J™™₯Jšœ œ\™{Jšœ œB™UJšœ œœ7™UJšœ œœu™‰—J™Jšœ- œ  œ œ œS  œ  œ  œs œŸ œΔ™ΗJ™—™ Jšœύ™ύJ™šœœž˜4J˜—Jšœ œœ˜%šœœœ˜Jšœž˜-Jšœ ž˜šœ œ˜Jšœ ž˜)Jšœ ž)˜5Jšœž;˜TJšœœž1˜NJš˜—Jšœ˜—Jšœœœœ ˜*J˜JšŸ œœœœ˜3šŸ œœœ˜.Jšœ™J™—JšŸœœœœ ˜-šŸœœ œ ˜+J™BJ™—JšŸœœœœ ˜<šŸœœœ ˜:J™BJ™—JšŸœœœœ ˜:šŸœœœœ ˜:J™-J™-J™—JšŸœœ(œœ ˜OšŸœœ"œ ˜D™AJšœ‡™‡—J˜—Jš Ÿœœ œœœ ˜PšŸœœ!œœ ˜IšœH™HJšœυ™υ—J˜—JšŸœœ œœ ˜EšŸœœœ ˜>šœ:™:JšœΊ™Ί—J˜—šœ œ˜)J˜—JšŸ œ ž œ ˜,šŸœ ž œ˜4J˜——™ šŸœœœ˜/JšœΙœœ™εJšœ€™€JšœΙ œ‡™ήJ™—šŸ œœ1œœ˜NJ™——™šŸœœ œ˜:J™*—J˜šœ œ˜JšœžB˜JJšœž-˜3Jšœž(˜.Jšœ˜J˜—šŸ œœ)˜;J™3J˜—šŸ œœœ˜0Jšœϊ œ•™–J™™J™›J™—šŸœœœ˜6JšœΟ™ΟJ™—JšŸœœ1œœ˜PšŸœœ1œœ˜VJ™——™JšŸ œœœ˜8šŸœœœ˜;Jšœœ7˜?J™@J™RJ™—Jšœœœœ˜1šŸœœ˜*šœ$™$JšœF™F—J™0J™—JšŸ œœ#œ˜9šŸ œœ#œ˜J˜—š Ÿœœœœœœ˜5J˜J˜—šŸœœœ˜,J˜—šŸœœœ œ œœœ˜RJ˜—šŸœœœœœ œ œœœ˜_J˜—šŸœœœ˜-J˜J˜—šŸœœ!œ˜J˜—JšŸœœœ˜'šŸœœœ˜*Jšœœ&˜.—J˜——™ šœ œ˜*J˜—šŸœœ˜Jš œ œœœœœœ˜:Jšœ,˜/Jšœœ˜šœ™Jšœ<™JšŸœœ"œ˜@JšŸœœ(˜5JšŸœœœ˜*JšŸœœœ˜0JšŸœœœ˜+JšŸ œœœ˜1JšŸœœ˜JšŸœœ˜ JšŸœœœœ˜@Jš Ÿœœœœœœ˜MJšŸœœœ˜/JšŸœœœ˜,JšŸœœœ˜0JšŸœœœ˜/JšŸ œœœ˜3JšŸœœJœ˜gJšŸœœHœ˜eJšŸœœœ˜+JšŸœœ1œ˜FJšŸ œœ1œ˜HJšŸœœ1œ˜NJšŸ œœ#œ˜;JšŸ œœ#œ˜?JšŸ œœœ˜:JšŸœœœ˜>JšŸœœ˜)JšŸ œœœ˜5JšŸœœœ˜9JšŸ œœ%˜4JšŸ œœ1œ˜IJšŸœœ1œ˜LJšŸ œœœ˜:JšŸœœœ˜>JšŸœœœ˜=JšŸœœœ˜AJšŸ œœ˜&JšŸ œœœ˜3JšŸœœœ˜.JšŸœœœ˜8JšŸœœœ˜:JšŸœœœ˜)JšŸœœœ˜,J˜J˜—J™—Jšœ˜—…—,s·