<> <> <<>> DIRECTORY Commander, Convert, FS, IO, Imager, ImagerBasic, ImagerConic, Real, Rope, UFFileManager, UFPressFontReader, SDtoSF; SDtoSFImpl: CEDAR PROGRAM IMPORTS Commander, Convert, FS, IO, ImagerConic, Real, Rope, UFFileManager, UFPressFontReader EXPORTS SDtoSF SHARES Imager ~ BEGIN ROPE: TYPE ~ Rope.ROPE; Pair: TYPE ~ ImagerBasic.Pair; Trajectory: TYPE ~ Imager.Trajectory; TrajectoryRep: TYPE ~ Imager.TrajectoryRep; Outline: TYPE ~ Imager.Outline; Polygon: TYPE ~ Imager.Polygon; Coeffs: TYPE ~ RECORD [c0, c1, c2, c3: ImagerBasic.Pair]; Sub: PROC [a: Pair, b: Pair] RETURNS [Pair] ~ INLINE { RETURN[[a.x-b.x, a.y-b.y]] }; Add: PROC [a: Pair, b: Pair] RETURNS [Pair] ~ INLINE { RETURN[[a.x+b.x, a.y+b.y]] }; Mul: PROC [a: Pair, s: REAL] RETURNS [Pair] ~ INLINE { RETURN[[a.x*s, a.y*s]] }; BezierToCoeffs: PROC [bezier: ImagerBasic.Bezier] RETURNS[coeffs: Coeffs] ~ { <> <> <> <> <> t: Pair _ Mul[Sub[bezier.b2,bezier.b1],3]; coeffs.c0 _ bezier.b0; coeffs.c1 _ Mul[Sub[bezier.b1, bezier.b0], 3]; coeffs.c2 _ Sub[t, coeffs.c1]; coeffs.c3 _ Sub[bezier.b3, Add[bezier.b0, t]]; RETURN [coeffs]; }; MapTrajectory: ImagerBasic.PathMapType = { t: Trajectory = NARROW[data]; move[t.lp]; FOR x: Trajectory _ t, x.prev UNTIL x.prev=NIL DO p0: Pair = x.prev.lp; WITH x SELECT FROM x: REF TrajectoryRep[line] => line[p0]; x: REF TrajectoryRep[curve] => curve[x.p2, x.p1, p0]; x: REF TrajectoryRep[conic] => conic[x.p1, p0, x.r]; x: REF TrajectoryRep[move] => ERROR; ENDCASE => ERROR; ENDLOOP; }; MapTrajectoryList: ImagerBasic.PathMapType = { FOR x: LIST OF Trajectory _ NARROW[data], x.rest UNTIL x = NIL DO MapTrajectory[x.first, move, line, curve, conic] ENDLOOP; }; MapPolygon: ImagerBasic.PathMapType = { p: Polygon = NARROW[data]; IF p.length>0 THEN { move[p[0]]; FOR i: NAT IN[1..MIN[p.length, p.maxLength]) DO line[p[i]] ENDLOOP; }; }; SDCharToRope: PUBLIC PROC [sdName: ROPE, charCode: NAT, fiducial: INT] RETURNS [ROPE] ~ { stream: IO.STREAM _ IO.ROS[]; SDCharToStream[stream, sdName, charCode, fiducial]; RETURN [IO.RopeFromROS[stream]]; }; SDCharToStream: PUBLIC PROC [dest: IO.STREAM, sdName: ROPE, charCode: NAT, fiducial: INT] ~ { fontKey: UFPressFontReader.FontKey _ [UFFileManager.KeyOf[sdName], 0]; charInfo: UFPressFontReader.CharInfo _ UFPressFontReader.GetCharInfo[fontKey, VAL[charCode]]; pathMap: ImagerBasic.PathMapType; pathData: REF; [pathMap, pathData] _ UFPressFontReader.GetCharPath[fontKey, VAL[charCode]]; PathToStream[dest, pathMap, pathData, UFPressFontReader.Family[fontKey], DecodeFace[UFPressFontReader.Face[fontKey]], VAL[charCode], charInfo.widthX, charInfo.widthY, fiducial]; }; DecodeFace: PROC [faceCode: [0..255]] RETURNS [face: ROPE] ~ { IF faceCode IN [0..18) THEN { slope: ROPE ~ IF (faceCode MOD 2) = 0 THEN "Roman" ELSE "Italic"; weight: ROPE ~ SELECT (faceCode/2 MOD 3) FROM 0 => "Medum", 1 => "Bold", 2 => "Light", ENDCASE => ERROR; expansion: ROPE ~ SELECT (faceCode/6 MOD 3) FROM 0 => "Regular", 1 => "Condensed", 2 => "Expanded", ENDCASE => ERROR; face _ weight.Cat[" ", slope, " ", expansion]; } ELSE face _ Convert.RopeFromInt[faceCode]; }; OutlineToRope: PUBLIC PROC [outline: REF, family: ROPE, face: ROPE, charCode: NAT, widthx: REAL, widthy: REAL, fiducial: INT] RETURNS [ROPE] ~ { stream: IO.STREAM _ IO.ROS[]; OutlineToStream[stream, outline, family, face, charCode, widthx, widthy, fiducial]; RETURN [IO.RopeFromROS[stream]]; }; <<>> OutlineToStream: PUBLIC PROC [dest: IO.STREAM, outline: REF, family: ROPE, face: ROPE, charCode: NAT, widthx: REAL, widthy: REAL, fiducial: INT] ~ { WITH outline SELECT FROM o: Outline => PathToStream[dest, MapTrajectoryList, o.list, family, face, charCode, widthx, widthy, fiducial]; list: LIST OF Trajectory => PathToStream[dest, MapTrajectoryList, list, family, face, charCode, widthx, widthy, fiducial]; t: Trajectory => PathToStream[dest, MapTrajectory, t, family, face, charCode, widthx, widthy, fiducial]; p: Polygon => PathToStream[dest, MapPolygon, p, family, face, charCode, widthx, widthy, fiducial]; ENDCASE => ERROR; }; <<>> PathToStream: PUBLIC PROC [dest: IO.STREAM, pathMap: ImagerBasic.PathMapType, pathData: REF, family: ROPE, face: ROPE, charCode: NAT, widthx: REAL, widthy: REAL, fiducial: INT] ~ { Grid: PROC [vec: Pair] RETURNS [gridVec: Pair] ~ { gridVec.x _ Real.RoundLI[(vec.x)*fiducial]; gridVec.y _ Real.RoundLI[(vec.y)*fiducial]; }; CountCon: PROC RETURNS [maxBeziers: NAT _ 0] ~ { beziers: NAT _ 0; p0: Pair _ [0, 0]; Move: PROC [p: Pair] ~ {maxBeziers _ MAX[maxBeziers, beziers]; beziers _ 0; p0 _ Grid[p]}; Line: PROC [p: Pair] ~ {beziers _ beziers+1; p0 _ Grid[p]}; Curve: PROC [p1, p2, p3: Pair] ~ {beziers _ beziers+1; p0 _ Grid[p3]}; Conic: PROC [p1, p2: Pair, r: REAL] ~ {ImagerConic.ToCurves[p0, p1, p2, r, Curve]}; pathMap[pathData, Move, Line, Curve, Conic]; maxBeziers _ MAX[maxBeziers, beziers]; }; BezierSequenceRec: TYPE ~ RECORD[SEQUENCE length: NAT OF ImagerBasic.Bezier]; bezier: REF BezierSequenceRec _ NEW[BezierSequenceRec[CountCon[]]]; k: NAT _ 0; p0: Pair _ [0, 0]; Move: PROC [p: Pair] ~ { WriteCurrentOutline[]; p0 _ Grid[p]; }; Line: PROC [p: Pair] ~ { p _ Grid[p]; bezier[k] _ [ b0: p0, b1: [(p0.x+p0.x+p.x)/3, (p0.y+p0.y+p.y)/3], b2: [(p0.x+p.x+p.x)/3, (p0.y+p.y+p.y)/3], b3: p ]; k _ k+1; p0 _ p; }; Curve: PROC [p1, p2, p3: Pair] ~ { p1 _ Mul[p1, fiducial]; p2 _ Mul[p2, fiducial]; p3 _ Grid[p3]; bezier[k] _ [b0: p0, b1: p1, b2: p2, b3: p3]; k _ k+1; p0 _ p3; }; Conic: PROC [p1, p2: Pair, r: REAL] ~ {ImagerConic.ToCurves[p0, p1, p2, r, Curve]}; WriteCurrentOutline: SAFE PROC ~ CHECKED { IF k=0 THEN RETURN; dest.PutF["\n ((%d (", IO.int[k+1]]; FOR i: NAT IN [0..k) DO dest.PutF["(%d %d) ", IO.int[Real.RoundLI[bezier[i].b0.x]], IO.int[Real.RoundLI[bezier[i].b0.y]]]; ENDLOOP; dest.PutF["(%d %d)", IO.int[Real.RoundLI[bezier[0].b0.x]], IO.int[Real.RoundLI[bezier[0].b0.y]]]; dest.PutRope[")\n NIL ("]; FOR i: NAT IN [0..k) DO coeffs: Coeffs _ BezierToCoeffs[bezier[i]]; IF i>0 THEN dest.PutRope[" "]; dest.PutF["(%g %g", IO.real[coeffs.c1.x], IO.real[coeffs.c1.y]]; dest.PutF[" %g %g", IO.real[coeffs.c2.x*2.0], IO.real[coeffs.c2.y*2.0]]; dest.PutF[" %g %g)", IO.real[coeffs.c3.x*6.0], IO.real[coeffs.c3.y*6.0]]; ENDLOOP; dest.PutRope[")\n NATURAL))"]; k _ 0; }; dest.PutRope["\n((FAMILY "]; dest.PutRope[family]; dest.PutRope[") "]; dest.PutF[" (CHARACTER %d)\n", IO.int[charCode]]; dest.PutRope[" (FACE "]; dest.PutRope[face]; dest.PutRope[")\n"]; dest.PutF[" (WIDTH %d %d)\n", IO.int[Real.RoundLI[widthx*fiducial]], IO.int[Real.RoundLI[widthy*fiducial]]]; dest.PutF[" (FIDUCIAL %d %d)\n", IO.int[fiducial], IO.int[fiducial]]; dest.PutRope[" (SPLINES"]; pathMap[data: pathData, move: Move, line: Line, curve: Curve, conic: Conic]; WriteCurrentOutline[]; dest.PutRope["))\n"]; }; ConvertFile: PUBLIC PROC [sdName: ROPE, sfName: ROPE] ~ { fontKey: UFPressFontReader.FontKey _ [UFFileManager.KeyOf[sdName], 0]; dest: IO.STREAM _ FS.StreamOpen[sfName, $create]; bc, ec: CHAR; [bc, ec] _ UFPressFontReader.Range[fontKey]; FOR c: CHAR IN [bc..ec] DO SDCharToStream[dest, sdName, VAL[c], 15840]; ENDLOOP; dest.PutRope["\nSTOP\n"]; IO.Close[dest]; }; Break: PROC [char: CHAR] RETURNS [IO.CharClass] = { IF char = '_ OR char = '; THEN RETURN [break]; IF char = ' OR char = ' OR char = ', OR char = '\n THEN RETURN [sepr]; RETURN [other]; }; GetToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE _ NIL] = { rope _ stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token; }; SDtoSFCommand: Commander.CommandProc ~ { stream: IO.STREAM _ IO.RIS[cmd.commandLine]; outputName: ROPE _ GetToken[stream]; gets: ROPE _ GetToken[stream]; inputName: ROPE _ GetToken[stream]; IF NOT gets.Equal["_"] THEN { cmd.out.PutRope["Specify output _ input, please\n"]; RETURN; }; ConvertFile[inputName, outputName]; }; Commander.Register["SDtoSF", SDtoSFCommand, "Convert SD file to SF format (output _ input)"]; END.