SDtoSFImpl.mesa
Michael Plass, January 13, 1984 10:20 am
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
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] ~ {
Compute the cubic coefficients from the Bezier points.
c0 ← b0;
c1 ← 3(b1-b0);
c2 ← 3(b0-2b1+b2); [ = 3(b2-b1) - c1 ]
c3 ← -b0 +3(b1-b2) + b3; [ = b3 - (b0 + 3(b2-b1)) ]
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.