DIRECTORY
Basics USING [BytePair, CompareCard, Comparison],
CubicSplines USING [SplineType, KnotSequence, KnotSequenceRec, MakeSpline, X, Y],
CubicPaths USING [Path, EnumeratePath, PathFromCubic],
FS USING [ComponentPositions, ExpandName, StreamOpen],
GFileFormatDefs,
GriffinImageUtils,
Imager USING [Context, DoSaveAll, Error, Font, MaskFillTrajectory, MaskStrokeTrajectory, micasPerPoint, Move, RotateT, SetColor, SetFont, SetStrokeWidth, SetXRel, SetXY, SetYRel, ShowRope],
ImagerColor USING [ColorFromRGB, RGBFromHSV],
ImagerFont USING [Find, RopeWidth, Scale],
ImagerPath USING [LineTo, MoveTo, CurveTo, Trajectory, MoveToProc, CurveToProc],
IO USING [GetBlock, GetChar, SetIndex, STREAM],
MessageWindow USING [Append],
PrincOpsUtils USING [LongCopy],
RealConvert USING [Mesa5ToIeee],
RedBlackTree USING [Create, Insert, Lookup, Table],
Rope USING [Cat, Compare, Equal, FromProc, FromRefText, Substr];
OPEN GriffinImageUtils;
SplineType: TYPE ~ CubicSplines.SplineType;
ReadGriffinImage:
PUBLIC
ENTRY
PROC [name:
ROPE]
RETURNS [g: GriffinImage] ~
TRUSTED {
Monitors the current definition of ConvertReal
ENABLE UNWIND => NULL;
Name:
UNSAFE PROC [chars:
PACKED
ARRAY [0 .. GFileFormatDefs.cNameChars]
OF
CHARACTER]
RETURNS [rope:
ROPE ←
NIL] ~ {
GetChar:
PROC
RETURNS [c:
CHAR] ~
CHECKED {
index ← index+1;
c ← chars[index];
};
len, index: CARDINAL ← 0;
len ← LOOPHOLE[chars[0], CARDINAL];
rope ← Rope.FromProc[len, GetChar];
};
diskHandle: IO.STREAM;
gHeader: GFileFormatDefs.GFileHeader;
name ← FixFileName[name, ".griffin"];
diskHandle ← FS.StreamOpen[name];
gHeader ← ReadHeader[diskHandle]; --Set up header info
g ← NEW[GriffinImageRep[gHeader.numfigs]]; --Create top level structure
g.header ←
NEW[HeaderRep ← [
majorVersion: gHeader.majversion,
minorVersion: gHeader.minversion,
creatorName: Name[gHeader.creatorname],
portfolioName: Name[gHeader.portfolioname],
createTime: LOOPHOLE[gHeader.createtime]
]];
FOR figure:
CARDINAL
IN [1..g.nFigures)
DO
ReadFigure[g, figure, diskHandle, gHeader];
ENDLOOP;
};
ConvertRealFromMesa5:
PROC [in:
REAL]
RETURNS [
REAL] ~ {
RETURN [RealConvert.Mesa5ToIeee[LOOPHOLE[in]]];
};
ConvertRealFromReal:
PROC [in:
REAL]
RETURNS [
REAL] ~ {
RETURN [in]
};
ConvertReal: PROC [in: REAL] RETURNS [REAL];
ReadFigure:
INTERNAL
PROC [g: GriffinImage, f:
CARDINAL, diskHandle:
IO.
STREAM, gHeader: GFileFormatDefs.GFileHeader] ~
TRUSTED {
Reads the fth figure into the GriffinImage structure.
figureName: GFileFormatDefs.GFileFigureName;
hControl: GFileFormatDefs.GFileHardcopyController;
dControl: GFileFormatDefs.GFileDisplayController;
ReadFigureInformation:
INTERNAL
PROC ~
TRUSTED {
MoveToSector[diskHandle, gHeader.figure[f]];
ReadStructure[diskHandle, @figureName, GFileFormatDefs.lGFileFigureName];
ReadStructure[diskHandle, @hControl, GFileFormatDefs.lGFileHardcopyController];
ReadStructure[diskHandle, @dControl, GFileFormatDefs.lGFileDisplayController];
};
ConvertDisplayController:
INTERNAL
PROC [d: GFileFormatDefs.GFileDisplayController]
RETURNS [DisplayController] ~
TRUSTED {
RETURN [[
centerX: d.centerx,
centerY: d.centery,
width: d.width,
height: d.height,
xScale: ConvertReal[d.xscale],
yScale: ConvertReal[d.yscale],
gridXo: ConvertReal[d.gridxo],
gridYo: ConvertReal[d.gridyo],
gridSize: d.gridsize,
pairs: NIL
]];
};
ConvertHardcopyController:
INTERNAL
PROC [h: GFileFormatDefs.GFileHardcopyController]
RETURNS [GFileFormatDefs.GFileHardcopyController] ~
CHECKED {
RETURN [[
centerx: ConvertReal[h.centerx],
centery: ConvertReal[h.centery],
width: ConvertReal[h.width],
height: ConvertReal[h.height],
presscenterx: h.presscenterx,
presscentery: h.presscentery,
scale: ConvertReal[h.scale]
]];
};
Name:
INTERNAL
PROC [chars:
PACKED
ARRAY [0 .. GFileFormatDefs.figureNameChars]
OF
CHARACTER]
RETURNS [rope:
ROPE ←
NIL] ~
CHECKED {
GetChar:
PROC
RETURNS [c:
CHAR] ~
CHECKED {
index ← index+1;
c ← chars[index];
};
len, index: CARDINAL ← 0;
len ← LOOPHOLE[chars[0], CARDINAL];
rope ← Rope.FromProc[len, GetChar];
};
font: FontDir;
styles: Styles;
objects: Objects;
g.figures[f] ← NEW[FigureRep];
ReadFigureInformation[];
font ← ReadFontDir[diskHandle];
styles ← ReadStyles[diskHandle];
objects ← ReadObjects[diskHandle];
g.figures[f]^ ← [
font: font,
styles: styles,
objects: objects,
display: ConvertDisplayController[dControl],
hardcopy: ConvertHardcopyController[hControl],
name: Name[figureName]
];
};
ReadFontDir:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM]
RETURNS [font: FontDir] ~
UNCHECKED {
nFonts: CARDINAL ~ ReadCardinal[diskHandle];
font ← NEW[FontDirRep[nFonts]];
FOR f:
CARDINAL
IN [0..nFonts)
DO
font[f] ← ReadFont[diskHandle];
ENDLOOP;
};
ReadFont:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM]
RETURNS [f: Font] ~
UNCHECKED {
Name:
INTERNAL
PROC [chars:
PACKED
ARRAY [0 .. GFileFormatDefs.fontChars]
OF
CHARACTER]
RETURNS [rope:
ROPE ←
NIL] ~
CHECKED {
GetChar:
PROC
RETURNS [c:
CHAR] ~
CHECKED {
index ← index+1;
c ← chars[index];
};
len, index: CARDINAL ← 0;
len ← LOOPHOLE[chars[0], CARDINAL];
rope ← Rope.FromProc[len, GetChar];
};
font: REF GFileFormatDefs.GFileFont ← NEW[GFileFormatDefs.GFileFont];
ReadStructure[diskHandle, LOOPHOLE[font], GFileFormatDefs.lGFileFont];
f ← [
points: font.points,
face: font.face,
rotation: font.rotation,
name: Name[font.char]
];
};
ReadStyles:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM]
RETURNS [styles: Styles] ~
UNCHECKED {
styleCount: CARDINAL ← ReadCardinal[diskHandle];
styles ← NEW[StylesRep[styleCount]];
FOR style:
CARDINAL
IN [0..styles.nStyles)
DO
styles[style] ← ReadStyle[diskHandle];
ENDLOOP;
};
ReadStyle:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM]
RETURNS [style: Style] ~
UNCHECKED {
MakeEnd:
INTERNAL
PROC [endType:
CARDINAL, dx, dy, a, b, c:
REAL]
RETURNS [End] ~
CHECKED {
N.B.: Does conversion on the REALs found
RETURN [[
type: LOOPHOLE[endType],
dx: ConvertReal[dx],
dy: ConvertReal[dy],
a: ConvertReal[a],
b: ConvertReal[b],
c: ConvertReal[c]
]]
};
Name:
INTERNAL
PROC [chars:
PACKED
ARRAY [0 .. GFileFormatDefs.sNameChars]
OF
CHARACTER]
RETURNS [rope:
ROPE ←
NIL] ~
CHECKED {
GetChar:
PROC
RETURNS [c:
CHAR] ~
CHECKED {
index ← index+1;
c ← chars[index];
};
len, index: CARDINAL ← 0;
len ← LOOPHOLE[chars[0], CARDINAL];
rope ← Rope.FromProc[len, GetChar];
};
s: REF GFileFormatDefs.GFileStyle ← NEW[GFileFormatDefs.GFileStyle];
ReadStructure[diskHandle, LOOPHOLE[s], GFileFormatDefs.lGFileStyle];
style ← NEW[StyleRep];
style^ ← [
color: [hue: s.hue, saturation: s.saturation, brightness: s.brightness],
areaColor: [hue: s.ahue, saturation: s.asaturation, brightness: s.abrightness],
textBackgroundColor: [hue: s.bhue, saturation: s.bsaturation, brightness: s.bbrightness],
fillArea: s.afilled,
outlineArea: s.aoutlined,
useTextBackground: s.background,
beginning: MakeEnd[s.send, s.bdx, s.bdy, s.ba, s.bb, s.bc],
end: MakeEnd[s.eend, s.edx, s.edy, s.ea, s.eb, s.ec],
thickness: ConvertReal[s.thickness],
font: s.fontid-1, --????
dashedness: s.dashedness,
anchor: LOOPHOLE[s.anchor],
junction: LOOPHOLE[s.junction],
textRotation: LOOPHOLE[s.torient],
styleName: Name[s.stylename]
];
};
initialCurvePart: CurvePart ~ [cyclicSpline [[naturalUM, NIL]]];
initialVariant: Variant ~ [curve [initialCurvePart]];
initialObjectRep: ObjectRep ~ [TRUE, inVisible, 0, 0, initialVariant];
ReadObjects:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM]
RETURNS [objects: Objects] ~
UNCHECKED {
NOTE: diskHandle must be set up ready to read the object count!!!!!!!!!!!!!
ReadObject:
INTERNAL
UNSAFE
PROC
RETURNS [object: Object ←
NEW[ObjectRep ← initialObjectRep]] ~
UNCHECKED {
ReadVariant:
INTERNAL
UNSAFE
PROC
RETURNS [variant: Variant ← initialVariant] ~
UNCHECKED {
ReadVEC:
INTERNAL
UNSAFE
PROC
RETURNS [vec:
VEC] ~
UNCHECKED {
point: GFileFormatDefs.GFilePoint;
ReadStructure[diskHandle, @point, GFileFormatDefs.lGFilePoint];
vec.x ← ConvertReal[point.x];
vec.y ← ConvertReal[point.y];
};
ReadCurvePart:
INTERNAL
UNSAFE
PROC
RETURNS [cp: CurvePart ← initialCurvePart] ~
UNCHECKED {
ReadLink:
INTERNAL
UNSAFE
PROC
RETURNS [link: Link] ~
UNCHECKED {
Main body of ReadCurvePart
knotWord: GFileFormatDefs.GFileKnotWord;
ReadStructure[diskHandle, @knotWord, GFileFormatDefs.lGFileKnotWord];
IF knotWord.knotcount=0 THEN ERROR; --Bad link
link ← NEW[LinkRep[knotWord.knotcount]];
link.degree ← LOOPHOLE[knotWord.knottype];
FOR knot:
CARDINAL
IN [0..link.nKnots)
DO
link.knots[knot] ← ReadVEC[];
ENDLOOP;
}; --ReadLink
nLinks: CARDINAL ← ReadCardinal[diskHandle];
Main body of ReadCurvePart
SELECT gObject.trajtype
FROM
GFileFormatDefs.typeLinkedTraj => {
linkPart: LinkPart ← NEW[LinkPartRep[nLinks]];
linkPart.splineType ← ConvertSplineType[gObject.splinetype];
FOR link:
CARDINAL
IN [0..nLinks)
DO
linkPart.links[link] ← ReadLink[];
ENDLOOP;
cp ← [linked [linkPart]];
};
GFileFormatDefs.typeCSTraj => {
IF nLinks#1 THEN ERROR --Impossible cyclic spline
ELSE {
splineType: SplineType ← ConvertSplineType[gObject.splinetype];
SELECT splineType
FROM
naturalUM => splineType ← cyclicUM;
naturalAL => splineType ← cyclicAL;
ENDCASE;
cp ← [cyclicSpline [[splineType, ReadLink[]]]];
};
};
ENDCASE => ERROR; --Invalid trajectory
}; --ReadCurvePart
ReadCaptionPart:
INTERNAL
UNSAFE
PROC
RETURNS [cp: CaptionPart] ~
UNCHECKED {
ReadString:
PROCEDURE
RETURNS [r:
ROPE] ~
TRUSTED {
length: CARDINAL ← LOOPHOLE[IO.GetChar[diskHandle], CARDINAL];
t: REF TEXT ← NEW[TEXT[length]];
IF IO.GetBlock[diskHandle,t,0,length] # length THEN ERROR; --Possible disk problem
r ← Rope.FromRefText[t];
always read an even number of bytes: string length + string chars MOD 2 = 0
IF (length+1) MOD 2 # 0 THEN [] ← IO.GetChar[diskHandle];
};
cp.position ← ReadVEC[];
cp.text ← ReadString[];
};
Main body of ReadVariant
SELECT gObject.objtype
FROM
GFileFormatDefs.typeCurveObject => {
variant ← [curve [ReadCurvePart[]]];
};
GFileFormatDefs.typeAreaObject => {
variant ← [area [ReadCurvePart[]]];
};
GFileFormatDefs.typeCaptionObject => {
variant ← [caption [ReadCaptionPart[]]];
};
ENDCASE => ERROR;
}; --ReadVariant
gObject: REF GFileFormatDefs.GFileObject ← NEW[GFileFormatDefs.GFileObject];
Main body of ReadObject
ReadStructure[diskHandle, LOOPHOLE[gObject], GFileFormatDefs.lGFileObject];
object^ ← [
hidden: gObject.hidewindow,
visibility: LOOPHOLE[gObject.visible],
style: gObject.style-1, --Fence-post correction
cluster: gObject.cluster,
variant: ReadVariant[]
];
}; --ReadObject
objectCount: CARDINAL ~ ReadCardinal[diskHandle];
Main body of ReadObjects
objects ← NEW[ObjectsRep[objectCount]];
FOR index:
CARDINAL
IN [0..objectCount)
DO
objects[index] ← ReadObject[];
ENDLOOP;
}; --ReadObjects
ConvertSplineType:
PROC [splineTypeInFile:
CARDINAL]
RETURNS [SplineType] ~ {
Dependent on definition of SplineType: TYPE ~ {naturalUM,cyclicUM,naturalAL,cyclicAL,bezier,bsplineInterp,bspline,crspline};
RETURN [
SELECT splineTypeInFile
FROM
IN [GFileFormatDefs.typeNUMSpline..GFileFormatDefs.typeCRSpline] => LOOPHOLE[splineTypeInFile],
ENDCASE => ERROR --Illegal spline type
];
};
charsPerPage: CARDINAL ~ 512;
MoveToSector:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM, si: GFileFormatDefs.SectorIndex] ~
UNCHECKED {
IO.SetIndex[diskHandle, INTEGER[si*charsPerPage]];
};
ReadStructure:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM, p:
LONG
POINTER, l:
CARDINAL] ~
UNCHECKED {
from: LONG POINTER;
b: REF TEXT ← NEW[TEXT[l*2]];
IF
IO.GetBlock[diskHandle, b, 0, 2*l] # 2*l
THEN ERROR;
from ← LOOPHOLE[b,LONG POINTER]+2; --start of bytes
PrincOpsUtils.LongCopy[from,l,p];
};
ReadCardinal:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM]
RETURNS [
CARDINAL] ~
UNCHECKED {
high, low: CHARACTER;
word: Basics.BytePair;
high ← IO.GetChar[diskHandle];
low ← IO.GetChar[diskHandle];
word.high ← LOOPHOLE[high]; word.low ← LOOPHOLE[low];
RETURN[LOOPHOLE[word]];
};
ReadHeader:
INTERNAL
UNSAFE
PROC [diskHandle:
IO.
STREAM]
RETURNS [header: GFileFormatDefs.GFileHeader] ~
UNCHECKED {
h: POINTER TO GFileFormatDefs.GFileHeader ~ @header;
IO.SetIndex[diskHandle,0];
ReadStructure[diskHandle, h, GFileFormatDefs.lGFileHeader];
ConvertReal ←
IF (h.majversion=1
AND h.minversion
IN [0..3])
THEN ConvertRealFromMesa5
ELSE ConvertRealFromReal;
Version 1.4 is the first with the Ieee floating point format.
We need to set up to convert the reals for older versions.
};
FixFileName:
INTERNAL
PROC [oldname, extension:
ROPE]
RETURNS [newname:
ROPE] ~ {
cp: FS.ComponentPositions;
dirOmitted: BOOL;
[newname, cp, dirOmitted] ← FS.ExpandName[oldname];
newname ← Rope.Cat[Rope.Substr[base: newname, len: cp.base.start+cp.base.length], extension];
IF dirOmitted THEN newname ← Rope.Substr[base: newname, start: cp.base.start];
};
CachedFont:
TYPE ~
RECORD [
key: REF GriffinImageUtils.Font,
imagerFont: Imager.Font
];
CompareFonts:
PROC [k, data:
REF]
RETURNS [c: Basics.Comparison] ~ {
f1: REF GriffinImageUtils.Font ~ NARROW[k];
f2: REF GriffinImageUtils.Font ~ NARROW[data, REF CachedFont].key;
SELECT
TRUE
FROM
(c ← Basics.CompareCard[f1.points, f2.points])#equal => RETURN;
(c ← Basics.CompareCard[f1.face, f2.face])#equal => RETURN;
(c ← Basics.CompareCard[f1.rotation, f2.rotation])#equal => RETURN;
ENDCASE => RETURN [Rope.Compare[f1.name, f2.name, FALSE]];
};
GetFontsKey:
PROC [data:
REF]
RETURNS [key:
REF] ~ {
RETURN [NARROW[data, REF CachedFont].key];
};
fontCache: RedBlackTree.Table ~ RedBlackTree.Create[GetFontsKey, CompareFonts];
FindFont:
PROC [font: GriffinImageUtils.Font]
RETURNS [imagerFont: Imager.Font ←
NIL] ~ {
key: REF GriffinImageUtils.Font ← NEW[GriffinImageUtils.Font ← font];
cachedFont: REF CachedFont ~ NARROW[RedBlackTree.Lookup[fontCache, key]];
IF cachedFont#NIL THEN RETURN [cachedFont.imagerFont];
{
--Here, it wasn't in the cache
FaceToExtension:
PROC
RETURNS [extension:
ROPE] ~ {
RETURN [
SELECT font.face
FROM
0 => "-mrr", --Plain
1 => "-mir", --Italics
2 => "-brr", --Bold
3 => "-bir", --Italics + Bold
ENDCASE => ERROR
]
};
msg: ROPE ← NIL; --Complaint about fonts
fontName: ROPE ← font.name;
fontExtension: ROPE ← FaceToExtension[];
Look up the font
WHILE imagerFont=
NIL
DO
imagerFont ← ImagerFont.Find[Rope.Cat["Xerox/PressFonts/", fontName, fontExtension] ! Imager.Error => {
SELECT
FALSE
FROM
--Various recovery techniques. Note that the result order is to (1) try the font as specified, (2) look for a plain-faced version of the font, (3) look for Helvetica, but use the bold and/or italics, (4) use plain Helvetica, (5) give up and die.
Rope.Equal["-mrr", fontExtension] => {
fontExtension ← "-mrr";
};
Rope.Equal["Helvetica", fontName] => {
fontName ← "Helvetica";
fontExtension ← FaceToExtension[]; --
};
ENDCASE => GOTO Fail; --Leave the error uncaught
imagerFont ← NIL;
msg ← Rope.Cat[error.explanation, " Substituting Xerox/PressFonts/", fontName, fontExtension, "."];
CONTINUE;
EXITS Fail => NULL;
}];
ENDLOOP;
IF msg#NIL THEN MessageWindow.Append[msg, TRUE];
Scale and rotate (ignored for now) the font
imagerFont ← ImagerFont.Scale[font: imagerFont, s: PointsToFontSize[font.points]];
RedBlackTree.Insert[self: fontCache, dataToInsert: NEW[CachedFont ← [key, imagerFont]], insertKey: key];
};
};
PointsToFontSize:
PROC [points:
REAL]
RETURNS [fontSize:
REAL] ~
INLINE {
RETURN [points*Imager.micasPerPoint]
};
GriffinObjectToImagerCalls:
PUBLIC
PROC [context: Imager.Context, object: Object, style: Style, fonts: FontDir] ~
CHECKED {
SetColor:
PROC [color: Color] ~ {
Imager.SetColor[context, ImagerColor.ColorFromRGB[ImagerColor.RGBFromHSV[[H: color.hue/255.0, S: color.saturation/255.0, V: color.brightness/255.0]]]];
};
SetThickness:
PROC [thickness:
REAL] ~ {
Imager.SetStrokeWidth[context, thickness];
};
PlayCurvePart:
PROC [cp: CurvePart, closed:
BOOL] ~ {
path: ImagerPath.Trajectory;
first: BOOLEAN ← TRUE;
moveTo: ImagerPath.MoveToProc ← firstMoveTo;
nullMoveTo: ImagerPath.MoveToProc = {};
firstMoveTo: ImagerPath.MoveToProc = TRUSTED {
path ← ImagerPath.MoveTo[p]; moveTo ← nullMoveTo};
curveTo: ImagerPath.CurveToProc = {path ← ImagerPath.CurveTo[path, p1, p2, p3]};
linkToCubicPath:
PROC [cubicLink: Link, splineType: CubicSplines.SplineType]
RETURNS[cubicPath: CubicPaths.Path] = {
cyclic: BOOLEAN ← splineType=cyclicAL OR splineType=cyclicUM;
nKnots: CARDINAL ← IF cyclic THEN cubicLink.nKnots+1 ELSE cubicLink.nKnots;
knots: CubicSplines.KnotSequence ← NEW[CubicSplines.KnotSequenceRec[nKnots]];
FOR i:
CARDINAL
IN [0..cubicLink.nKnots)
DO
knots[i][CubicSplines.X] ← cubicLink[i].x;
knots[i][CubicSplines.Y] ← cubicLink[i].y;
ENDLOOP;
IF cyclic THEN {
knots[cubicLink.nKnots][CubicSplines.X] ← cubicLink[0].x;
knots[cubicLink.nKnots][CubicSplines.Y] ← cubicLink[0].y;
};
cubicPath ← CubicPaths.PathFromCubic[CubicSplines.MakeSpline[knots, splineType]];
RETURN[cubicPath];
};
WITH cp
SELECT
FROM
links: linked CurvePart => {
--degree=1 for lines, 3 for cubics.
splineType: CubicSplines.SplineType ← links.linked.splineType;
FOR linkIndex:
CARDINAL
IN [0..links.linked.nLinks)
DO
link: Link ~ links.linked.links[linkIndex];
IF link.degree=3
THEN {
--cubic
cubicPath: CubicPaths.Path ← linkToCubicPath[link, splineType];
CubicPaths.EnumeratePath[cubicPath, moveTo, curveTo];
}
ELSE {
--assume lines
moveTo[link[0]];
FOR knotIndex:
CARDINAL
IN [1..link.nKnots)
DO
path ← ImagerPath.LineTo[path, link[knotIndex]];
ENDLOOP;
};
ENDLOOP;
IF closed THEN path ← ImagerPath.LineTo[path, links.linked.links[0].knots[0]];
};
cyclic: cyclicSpline CurvePart => {
cubicPath: CubicPaths.Path ←
linkToCubicPath[cyclic.cyclicSpline.link, cyclic.cyclicSpline.splineType];
CubicPaths.EnumeratePath[cubicPath, moveTo, curveTo];
};
ENDCASE => ERROR;
IF closed
AND style.fillArea
THEN {
SetColor[style.areaColor];
Imager.MaskFillTrajectory[context, path];
};
IF ~closed
OR style.outlineArea
THEN {
SetColor[style.color];
Imager.SetStrokeWidth[context, style.thickness];
Imager.MaskStrokeTrajectory[context, path];
};
};
WITH object.variant
SELECT
FROM
caption: caption Variant => {
imagerFont: Imager.Font ~ FindFont[fonts[style.font]];
length: REAL;
SetColor[style.color];
Imager.SetFont[context, imagerFont];
length ← ImagerFont.RopeWidth[imagerFont, caption.caption.text].x;
Imager.SetXY[context, caption.caption.position];
Imager.SetYRel[context, -PointsToFontSize[fonts[style.font].points]];
Imager.Move[context];
SELECT style.textRotation
FROM
d90 => Imager.RotateT[context, 90];
d180 => Imager.RotateT[context, 180];
d270 => Imager.RotateT[context, 270];
ENDCASE;
SELECT style.anchor
FROM
left => NULL;
right => Imager.SetXRel[context, -length];
center => Imager.SetXRel[context, -length/2];
ENDCASE => ERROR;
Imager.ShowRope[context, caption.caption.text];
};
curve: curve Variant => PlayCurvePart[curve.curve, FALSE];
area: area Variant => PlayCurvePart[area.curve, TRUE];
ENDCASE => ERROR;
};
GriffinToImagerCalls:
PUBLIC
PROC [context: Imager.Context, g: GriffinImage] ~
CHECKED {
FOR fIndex:
CARDINAL
IN [
FIRST[ValidFigRange]..g.nFigures)
DO
figure: Figure ~ g.figures[fIndex];
FOR oIndex:
CARDINAL
IN [0..figure.objects.nObjects)
DO
PlayObject:
PROC ~ {
GriffinObjectToImagerCalls[context, object, style, figure.font];
};
object: Object ~ figure.objects[oIndex];
style: Style ~ figure.styles[object.style];
IF ~object.hidden THEN Imager.DoSaveAll[context, PlayObject];
ENDLOOP;
ENDLOOP;
};