<> <> DIRECTORY Commander, GFileFormatDefs, Graphics, GriffinToJaM, IO, NameSymbolTable, PairList, PutGet, ReadGriffin, Real, Rope, SplineDefs, StyleDefs, TextEdit, TextNode, GraphicsBasic USING [Vec], CGPath USING [Generate]; GriffinToJaMImpl: CEDAR PROGRAM IMPORTS Commander, IO, PairList, PutGet, ReadGriffin, Rope, TextEdit, TextNode, Real, CGPath EXPORTS GriffinToJaM = { ROPE: TYPE = Rope.ROPE; topScreenCoord: INTEGER = 808; <> Regular: CARDINAL = 0; Italic: CARDINAL = 1; Bold: CARDINAL = 2; BoldItalic: CARDINAL = Bold + Italic; Rot0Degrees: CARDINAL = 0; Rot90Degrees: CARDINAL = 5400; Rot180Degrees: CARDINAL = 10800; Rot270Degrees: CARDINAL = 16200; ViewType: TYPE = {main, alternate, both}; GriffinToJaM: Commander.CommandProc ~ { fileName: ROPE; jamFileName: ROPE; stream: IO.STREAM _ IO.RIS[cmd.commandLine]; FileNameBreakProc: PROC [char: CHAR] RETURNS [IO.CharClass] = { IF char = ' OR char = ' OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr]; RETURN [other]; }; WHILE NOT IO.EndOf[stream] DO fileName _ NIL; fileName _ IO.GetTokenRope[stream, FileNameBreakProc ! IO.EndOfStream => CONTINUE].token; IF fileName # NIL THEN { cmd.out.PutRope[IO.PutFR["Converting %g to JaM . . . ", IO.rope[fileName]]]; ReadGriffin.ConvertFile[fileName ! ReadGriffin.GriffinFileError => {msg _ why; GOTO FileProblem}]; jamFileName _ ReadGriffin.FixFileName[fileName, ".JaM"]; PutClusters[jamFileName]; cmd.out.PutRope[IO.PutFR["into %g\n", IO.rope[jamFileName]]]; }; ENDLOOP; EXITS FileProblem => RETURN[$Failure, msg]; }; PutClusters: PUBLIC PROCEDURE[fileName: ROPE] = { thisCluster: CARDINAL; clusterNumber: CARDINAL _ 0; figureName: ROPE _ Rope.Substr[fileName, 0, Rope.Find[fileName, "."]]; figureRoot: TextNode.Ref; figureNode, clusterNode: TextNode.RefTextNode; clusterX, clusterY: INTEGER _ LAST[INTEGER]; objectBBox: PROC[leftPart, rightPart: REF ANY] = { IF NARROW[leftPart, REF CARDINAL]^=thisCluster THEN { refObjectId: REF CARDINAL _ NARROW[rightPart]; griffinObject: ReadGriffin.ObjectRef _ NARROW[PairList.Right[ReadGriffin.objectMap, EqualCardinals, refObjectId]]; clusterX _ MIN[clusterX, griffinObject^.bleft]; clusterY _ MIN[clusterY, topScreenCoord-griffinObject^.bbottom]; }; }; doObject: PROC[leftPart, rightPart: REF ANY] = { IF NARROW[leftPart, REF CARDINAL]^=thisCluster THEN { IF clusterNode=NIL THEN { clusterNumber _ clusterNumber+1; clusterNode _ PutClusterNode[figureRoot, figureNode, clusterNumber, clusterX, clusterY]}; PutObjectNode[figureRoot, clusterNode, NARROW[rightPart, REF CARDINAL], clusterX, clusterY]}; }; figureNode _ PutFigureNode[figureName]; figureRoot _ TextEdit.DocFromNode[figureNode]; FOR thisCluster IN [ReadGriffin.firstCluster .. ReadGriffin.lastCluster] DO clusterNode _ NIL; clusterX _ clusterY _ LAST[INTEGER]; PairList.ForAllPairs[ReadGriffin.clusterMap, objectBBox]; PairList.ForAllPairs[ReadGriffin.clusterMap, doObject]; IF clusterNode#NIL THEN PutPopNode[figureRoot, clusterNode]; ENDLOOP; [] _ PutGet.ToFile[fileName, figureRoot]; }; PutFigureNode: PROCEDURE[figureName: ROPE] RETURNS[node: TextNode.RefTextNode] = { rope: ROPE _ Rope.Cat["% Tioga Artwork figure for ", figureName]; node _ TextEdit.FromRope[rope]; RETURN[node]; }; PutClusterNode: PROCEDURE[figureRoot: TextNode.Ref, figureNode: TextNode.RefTextNode, cluster: CARDINAL, clusterX, clusterY: INTEGER] RETURNS[node: TextNode.RefTextNode] = { node _ InsertNodeAfterChildrenOf[figureNode]; [] _ TextEdit.AppendRope[figureRoot, node, IO.PutFR["%% Cluster %d\n.pushdc %d %d .translate", IO.card[cluster], IO.int[clusterX], IO.int[clusterY]]]; RETURN[node]; }; PutPopNode: PROCEDURE[figureRoot: TextNode.Ref, clusterNode: TextNode.RefTextNode] = { popNode: TextNode.RefTextNode _ InsertNodeAfterChildrenOf[clusterNode]; [] _ TextEdit.AppendRope[figureRoot, popNode, ".popdc"]; }; PutObjectNode: PROCEDURE[figureRoot: TextNode.Ref, clusterNode: TextNode.RefTextNode, refObjectId: REF CARDINAL, clusterX, clusterY: INTEGER] = { griffinObject: ReadGriffin.ObjectRef _ NARROW[PairList.Right[ReadGriffin.objectMap, EqualCardinals, refObjectId]]; objectNode: TextNode.RefTextNode _ InsertNodeAfterChildrenOf[clusterNode]; [] _ TextEdit.AppendRope[figureRoot, objectNode, IO.PutFR["%% Object %d", IO.card[refObjectId^]]]; SELECT griffinObject^.objtype FROM GFileFormatDefs.typeCurveObject, GFileFormatDefs.typeAreaObject => PutPathNode[figureRoot, objectNode, griffinObject, refObjectId, clusterX, clusterY]; GFileFormatDefs.typeCaptionObject => PutCaptionNode[figureRoot, objectNode, griffinObject, refObjectId, clusterX, clusterY]; ENDCASE; }; PutPathNode: PROCEDURE[figureRoot: TextNode.Ref, objectNode: TextNode.RefTextNode, griffinObject: ReadGriffin.ObjectRef, refObjectId: REF CARDINAL, clusterX, clusterY: INTEGER] = { pathNode: TextNode.RefTextNode _ InsertNodeAfterChildrenOf[objectNode]; refStyleId: REF CARDINAL _ NEW[CARDINAL _ griffinObject^.style]; griffinStyle: ReadGriffin.StyleRef _ NARROW[PairList.Right[ReadGriffin.styleMap, EqualCardinals, refStyleId]]; areaColor, outlineColor: ReadGriffin.ColorRef _ NIL; pathType: ROPE _ NIL; lineWeight: REAL _ 0; pathRef: ReadGriffin.PathRef; SELECT griffinObject^.objtype FROM GFileFormatDefs.typeAreaObject => { IF griffinStyle^.afilled THEN { areaColor _ FindColor[griffinStyle^.ahue, griffinStyle^.asaturation, griffinStyle^.abrightness]; pathType _ "filled"}; IF griffinStyle^.aoutlined THEN { outlineColor _ FindColor[griffinStyle^.hue, griffinStyle^.saturation, griffinStyle^.brightness]; pathType _ IF griffinStyle^.afilled THEN "filled+outlined" ELSE "outlined"; lineWeight _ ScalePressToScreenCoord[griffinStyle^.thickness]}}; GFileFormatDefs.typeCurveObject => { outlineColor _ FindColor[griffinStyle^.hue, griffinStyle^.saturation, griffinStyle^.brightness]; pathType _ "outlined"; lineWeight _ ScalePressToScreenCoord[griffinStyle^.thickness]}; ENDCASE; [] _ TextEdit.AppendRope[figureRoot, objectNode, IO.PutFR["\n.pushdc %d %d .translate", IO.int[griffinObject^.bleft-clusterX], IO.int[topScreenCoord-griffinObject^.bbottom-clusterY]]]; <> <> TRUSTED { pathRef _ LOOPHOLE[PairList.Right[ReadGriffin.pathMap, EqualCardinals, refObjectId]] }; [] _ TextEdit.AppendRope[figureRoot, pathNode,PathToRope[pathRef]]; SELECT pathType FROM "filled" => [] _ TextEdit.AppendRope[figureRoot, pathNode, IO.PutFR["%g .drawarea", IO.rope[areaColor.name]]]; "outlined" => [] _ TextEdit.AppendRope[figureRoot, pathNode, IO.PutFR["%g %g 2 .drawstroke", --2=round ends IO.rope[outlineColor.name], IO.real[lineWeight]]]; "filled+outlined" => { [] _ TextEdit.AppendRope[figureRoot, pathNode, IO.PutFR["%g .drawarea\n", IO.rope[areaColor.name]]]; [] _ TextEdit.AppendRope[figureRoot, pathNode,PathToRope[pathRef]]; [] _ TextEdit.AppendRope[figureRoot, pathNode, IO.PutFR["%g %g 2 .drawstroke", --2=round ends IO.rope[outlineColor.name], IO.real[lineWeight]]]; }; ENDCASE => ERROR; [] _ TextEdit.AppendRope[figureRoot, pathNode, " .popdc"]; }; PutCaptionNode: PROCEDURE[figureRoot: TextNode.Ref, objectNode: TextNode.RefTextNode, griffinObject: ReadGriffin.ObjectRef, refObjectId: REF CARDINAL, clusterX, clusterY: INTEGER] = { captionNode: TextNode.RefTextNode _ InsertNodeAfterChildrenOf[objectNode]; caption: ReadGriffin.CaptionRef _ NARROW[PairList.Right[ReadGriffin.captionMap, EqualCardinals, refObjectId]]; refStyleId: REF CARDINAL _ NEW[CARDINAL _ griffinObject^.style]; griffinStyle: ReadGriffin.StyleRef _ NARROW[PairList.Right[ReadGriffin.styleMap, EqualCardinals, refStyleId]]; refFontId: REF CARDINAL _ NEW[CARDINAL _ griffinStyle^.fontid]; griffinFont: ReadGriffin.FontRef _ NARROW[PairList.Right[ReadGriffin.fontMap, EqualCardinals, refFontId]]; family, face, charRotation, lineFormatting: ROPE; fontName: ROPE; size: REAL; textRotation: INTEGER; textColor: ReadGriffin.ColorRef; i: CARDINAL; bold, italic: BOOLEAN _ FALSE; FOR i IN [1 .. LOOPHOLE[griffinFont^.char[0],CARDINAL]] DO family _ Rope.Cat[family, Rope.FromChar[griffinFont^.char[i]]]; ENDLOOP; size _ griffinFont^.points; SELECT griffinFont^.face FROM Regular => face _ "regular"; Italic => {face _ "italic"; italic _ TRUE}; Bold => {face _ "bold"; bold _ TRUE}; BoldItalic => {face _ "bold+italic"; bold _ TRUE; italic _ TRUE}; ENDCASE=> face _ "regular"; charRotation _ SELECT griffinFont^.rotation FROM Rot0Degrees => "0", Rot90Degrees => "90", Rot180Degrees => "180", Rot270Degrees => "270", ENDCASE => "0"; lineFormatting _ SELECT griffinStyle^.anchor FROM GFileFormatDefs.typeLeftAnchor => "flushLeft", GFileFormatDefs.typeCenterAnchor => "centered", GFileFormatDefs.typeRightAnchor => "flushRight", ENDCASE => "flushLeft"; textRotation _ SELECT griffinStyle^.torient FROM GFileFormatDefs.typeRot0 => 0, GFileFormatDefs.typeRot90 => 90, GFileFormatDefs.typeRot180 => 180, GFileFormatDefs.typeRot270 => 270, ENDCASE => 0; textColor _ FindColor[griffinStyle^.hue, griffinStyle^.saturation, griffinStyle^.brightness]; [] _ TextEdit.AppendRope[figureRoot, objectNode, IO.PutFR["\n.pushdc %d %d .translate %d .rotate", IO.real[caption^.position.x-clusterX], IO.real[caption^.position.y-clusterY], IO.int[textRotation]]]; fontName _ IO.PutFR["(%g%g",IO.rope[family],IO.real[size]]; fontName _ Rope.Cat[fontName, (SELECT face FROM "italic" => "I", "bold" => "B", "bold+italic" => "BI", ENDCASE=> NIL), ".ks)"]; [] _ TextEdit.AppendRope[figureRoot, captionNode, IO.PutFR["%g .setfont topEdge %g (%g) %g 0 0 .setcp .drawtext .popdc", IO.rope[fontName],IO.rope[textColor.name], IO.rope[caption^.text],IO.rope[lineFormatting]]]; }; PathToRope: PROC [path: ReadGriffin.PathRef] RETURNS [ROPE] = { rope: ROPE; move: SAFE PROC[p: GraphicsBasic.Vec] = CHECKED { rope _ Rope.Cat[rope,IO.PutFR["%f %f %s ", IO.real[p.x], IO.real[p.y], IO.rope[" .moveto "]]]; }; line: SAFE PROC[p: GraphicsBasic.Vec] = CHECKED { rope _ Rope.Cat[rope,IO.PutFR["%f %f %s ", IO.real[p.x], IO.real[p.y], IO.rope[" .lineto "]]]; }; curve: SAFE PROC[b1,b2,b3: GraphicsBasic.Vec] = CHECKED { rope _ Rope.Cat[rope, IO.PutFR["%f %f %f %f ", IO.real[b1.x], IO.real[b1.y], IO.real[b2.x], IO.real[b2.y]]]; rope _ Rope.Cat[rope, IO.PutFR["%f %f %s", IO.real[b3.x], IO.real[b3.y], IO.rope[" .curveto "]]]; }; CGPath.Generate[path,move,line,curve]; RETURN[rope]; }; EqualCardinals: PairList.EqualProc = { l,r: CARDINAL; return _ FALSE; <> l _ NARROW[left,REF CARDINAL]^; r _ NARROW[right,REF CARDINAL]^; IF l=r THEN return _ TRUE; }; InsertNodeAfterChildrenOf: PROCEDURE[node: TextNode.RefTextNode, newnode: TextNode.RefTextNode _ NIL] RETURNS[TextNode.RefTextNode] = { p: TextNode.Ref; IF newnode = NIL THEN -- create a new node newnode _ TextNode.NewTextNode[] ELSE {-- unhook newnode from the tree p _ TextNode.Parent[newnode]; IF TextNode.FirstChild[p] = newnode THEN { -- newnode is a first sibling IF newnode.last THEN -- it was an only child p.child _ NIL ELSE -- its sibling is now the parents first child p.child _ newnode.next} ELSE { -- unhook newnode from the middle of a chain p _ TextNode.Previous[newnode, p]; p.next _ newnode.next; p.last _ newnode.last}}; <> IF TextNode.FirstChild[node]=NIL THEN { -- add newnode as a first child node.child _ newnode; newnode.next _ node; newnode.last _ TRUE} ELSE { -- finally, add newnode as sibling of last sibling p _ TextNode.LastChild[node]; newnode.next _ p.next; newnode.last _ p.last; p.next _ newnode; p.last _ FALSE}; RETURN[newnode]; }; FindColor: PROCEDURE[h, s, b: REAL] RETURNS[ReadGriffin.ColorRef] = { c: ReadGriffin.ColorRef _ ReadGriffin.colors; MatchColor: PROCEDURE[c: ReadGriffin.ColorRef, h, s, b: REAL] RETURNS[BOOLEAN] = INLINE { RETURN[c#NIL AND c.h=h AND c.s=s AND c.b=b]}; MakeColorName: PROCEDURE[n: CARDINAL] RETURNS[ROPE] = INLINE { RETURN[IO.PutFR["Color%d", IO.card[n]]]}; WHILE c#NIL DO IF MatchColor[c, h, s, b] THEN RETURN[c]; c _ c.next; ENDLOOP; ERROR; }; ScalePressToScreenCoord: PROCEDURE[a: REAL] RETURNS[INTEGER] = INLINE { RETURN[Real.RoundI[a*0.03125]]}; Commander.Register[key: "GriffinToJaM", proc: GriffinToJaM, doc: "convert a given Griffin file into equivalent JaM commands"]; }.