PressToIPImpl.mesa
Last edited by Shore; January 30, 1983 5:25 pm
Last edited by Wyatt; April 5, 1983 4:18 pm
DIRECTORY
CGCubic USING [Bezier, Coeffs, CoeffsToBezier, Flat, Split],
GraphicsBasic USING [Vec],
GraphicsColor USING [HSVToColor, ColorToIntensity],
IPEncodingOut USING [AppendInteger, AppendOp],
IPLimits USING [topFrameSize],
IPOperatorOut,
IPVariables USING [FrameVariable, ImagerVariable],
List USING [Comparison, CompareProc, Sort, Cons],
PressFontReader USING [Close, Font, FontInfoRec, FromFile, Handle, ListFonts],
PressToIP,
PressReader,
Real USING [RoundI, RoundLI],
Rope USING [Cat, Equal, Fetch, Find, Length, ROPE];
PressToIPImpl: PROGRAM
IMPORTS CGCubic, GraphicsColor, IPEncodingOut, IP: IPOperatorOut, List, PressFontReader, PressReader, Real, Rope
EXPORTS PressToIP = BEGIN OPEN PressToIP;
Positioning: TYPE = {relative, absolute};
Spacing: TYPE = {amplifying1, amplifying2, positioning};
OpenPressFile: PUBLIC PROCEDURE [pressFileName: Rope.ROPE] RETURNS [pressFile: PressFile] = {
pressFile ← PressReader.OpenPressFile[pressFileName !
PressReader.PressReaderError =>
SELECT errorCode FROM
FileNotAvailableForRead, AbortedBecauseGetFailed => ERROR Error[FileNotAvailable];
FileNotAPressFile => ERROR Error[FileNotAPressFile];
ENDCASE => REJECT
];
};
OpenOutputIPMaster: PUBLIC PROCEDURE [ipMasterName: Rope.ROPE] RETURNS [ipMaster: IPMaster] = {
ipMaster ← IP.BeginMaster[ipMasterName !
IP.Error => ERROR Error[FileNotAvailable]
];
};
Font: TYPE = REF FontRec;
FontRec: TYPE = RECORD[
encoding: NAT, -- fontSet*16+fontNumber, from Press file
fontNumber: NAT, -- font number in Interpress master
family: Rope.ROPE,
faceCode: Rope.ROPE,
sizeInMicas: INT,
rotation: INTEGER, -- in minutes of arc
widthX, widthY: REF WidthArray,
fixedWidthX, fixedWidthY: INTEGER
];
WidthArray: TYPE = ARRAY CHAR OF INTEGER;
Fonts: TYPE = RECORD[SEQUENCE max: NAT OF Font];
WidthX: PROC[f: Font, c: CHAR] RETURNS[INTEGER] = INLINE {
RETURN[IF f.widthX=NIL THEN f.fixedWidthX ELSE f.widthX[c]] };
WidthY: PROC[f: Font, c: CHAR] RETURNS[INTEGER] = INLINE {
RETURN[IF f.widthY=NIL THEN f.fixedWidthY ELSE f.widthY[c]] };
ConvertPressToInterpress: PUBLIC PROC[pressFile: PressFile, ipMaster: IPMaster,
usePriority: BOOLEANFALSE, fullInterpress: BOOLEANFALSE,
progressProc: ProgressProc ← NIL, progressData: REF ANY] = {
fonts: REF Fonts;
nFonts: INT ← 0;
tooManyFontsForFrame: BOOLEAN;
fontSets: INT ← 0; -- number of auxiliary composed operators/frames needed to hold >50 fonts
PageProc: PressReader.PageProc = {
ipGray: REAL ← 1.0; -- current gray in the Interpress master
ipAmplify: REAL ← 1.0; -- current amplifySpace value in the Interpress master
EntityProc: PressReader.EntityProc = { -- Xe, Ye, fontSet
Xe: INTEGER = entityTrailer.Xe;
Ye: INTEGER = entityTrailer.Ye;
hue, saturation, brightness: INT ← 0; -- current color in the Press file
fontNum: NAT ← 0; -- current font number
unset: INTEGER = FIRST[INTEGER];
spaceX, spaceY: INTEGER ← unset; -- current space width
pX, pY: INTEGER ← 0; -- current (entity-relative) position in the Press file
newPosition: BOOLTRUE; -- new position set, not yet reflected in IP master
newFont: BOOLTRUE; -- new font number set, curFont not yet updated
newAmplify: BOOLTRUE; -- amplifySpace must be recomputed
newColor: BOOLTRUE; -- new color set, not yet reflected in IP master
curFont: Font ← NIL; -- current font (if ~newFont)
skippingAlternative, inAlternative: BOOLEANFALSE;
SetPosition: PROC = {
ipMaster.SetXY[IP.int[pX+Xe], IP.int[pY+Ye]];
newPosition ← FALSE;
};
SetFont: PROC = {
key: NAT = entityTrailer.fontSet*16+fontNum;
IF skippingAlternative THEN RETURN;
IF nFonts=0 THEN RETURN;
IF curFont=NIL OR curFont.encoding#key THEN {
l: NAT ← 0;
u: NAT ← nFonts;
WHILE l <= u DO
i: NAT = (l+u)/2;
f: Font = fonts[i];
SELECT f.encoding FROM
> key => u ← i-1;
< key => l ← i+1;
= key => { curFont ← f; EXIT };
ENDCASE;
REPEAT FINISHED => ERROR Error[FontNotFound];
ENDLOOP;
IF tooManyFontsForFrame THEN {
ipMaster.FGet[IPVariables.FrameVariable[0]];
ipMaster.Get[curFont.fontNumber];
ipMaster.AppendInteger[
LOOPHOLE[IPVariables.ImagerVariable[showVec], CARDINAL]];
ipMaster.AppendOp[iset];
}
ELSE ipMaster.SetFont[curFont.fontNumber];
};
newFont ← FALSE;
newAmplify ← TRUE;
};
SetAmplify: PROC = {
sX, sY, dX, dY, s, d: INTEGER;
amplify: REAL;
IF newFont THEN SetFont[];
dX ← WidthX[curFont, ' ];
dY ← WidthY[curFont, ' ];
sX ← (IF spaceX=unset THEN dX ELSE spaceX);
sY ← (IF spaceY=unset THEN dY ELSE spaceY);
IF sY=0 AND dY=0 THEN { s ← sX; d ← dX }
ELSE IF sX=0 AND dX=0 THEN { s ← sY; d ← dY }
ELSE ERROR; -- not implemented
amplify ← REAL[s]/REAL[d];
IF amplify#ipAmplify THEN {
ipMaster.SetAmplifySpace[IF s=d THEN IP.int[1] ELSE IP.rational[s, d]];
ipAmplify ← amplify;
};
newAmplify ← FALSE;
};
SetColor: PROC = {
h: REAL = hue/255.0;
s: REAL = saturation/255.0;
v: REAL = brightness/255.0;
i: REAL = GraphicsColor.ColorToIntensity[GraphicsColor.HSVToColor[h, s, v]];
gray: REAL = 1.0-i;
IF gray#ipGray THEN ipMaster.SetGray[IP.real[ipGray ← gray]];
newColor ← FALSE;
};
showCharactersProc: PressReader.ShowCharactersProc = { -- [opCode, length, text]
HasSpaces: PROC[rope: Rope.ROPE] RETURNS[BOOL] = INLINE {
RETURN[rope.Find[" "]>=0] };
IF skippingAlternative THEN RETURN;
IF newColor THEN SetColor[];
IF newPosition THEN SetPosition[];
IF newFont THEN SetFont[]; -- Note: may set newAmplify
IF newAmplify AND HasSpaces[text] THEN SetAmplify[];
ipMaster.Show[text];
FOR i: INT IN[0..text.Length[]) DO
c: CHAR = text.Fetch[i];
IF c=' THEN {
pX ← pX+(IF spaceX=unset THEN WidthX[curFont, ' ] ELSE spaceX);
pY ← pY+(IF spaceY=unset THEN WidthY[curFont, ' ] ELSE spaceY);
}
ELSE {
pX ← pX+WidthX[curFont, c];
pY ← pY+WidthY[curFont, c];
};
ENDLOOP;
};
spacingProc: PressReader.SpacingProc = { -- [opCode, value]
IF skippingAlternative THEN RETURN;
IF value=unset THEN ERROR;
SELECT opCode FROM
setSpaceX, setSpaceXShort => spaceX ← value;
setSpaceY, setSpaceYShort => spaceY ← value;
resetSpace => spaceX ← spaceY ← unset;
ENDCASE => ERROR;
newAmplify ← TRUE;
};
spaceProc: PressReader.SpaceProc = { -- []
sX, sY: INTEGER;
IF skippingAlternative THEN RETURN;
IF newFont THEN SetFont[];
sX ← (IF spaceX=unset THEN WidthX[curFont, ' ] ELSE spaceX);
sY ← (IF spaceY=unset THEN WidthY[curFont, ' ] ELSE spaceY);
SELECT TRUE FROM
sY=0 => ipMaster.SetXRel[IP.int[sX]];
sX=0 => ipMaster.SetYRel[IP.int[sY]];
ENDCASE => ipMaster.SetXYRel[IP.int[sX], IP.int[sY]];
pX ← pX+sX; pY ← pY+sY;
};
positionProc: PressReader.PositionProc = {
IF skippingAlternative THEN RETURN;
SELECT opCode FROM
setX => pX ← value;
setY => pY ← value;
ENDCASE => ERROR;
newPosition ← TRUE;
};
colorProc: PressReader.ColorProc = {
IF skippingAlternative THEN RETURN;
SELECT opCode FROM
setHue => hue ← value;
setSaturation => saturation ← value;
setBrightness => brightness ← value;
ENDCASE => ERROR;
newColor ← TRUE;
};
fontProc: PressReader.FontProc = { -- [font]
IF font#fontNum THEN { fontNum ← font; newFont ← TRUE };
}; -- fontProc
alternativeProc: PressReader.AlternativeProc = {
IF (types = 0) AND (elBytes = 0) AND (dlBytes = 0) THEN
inAlternative ← skippingAlternative ← FALSE
ELSE IF inAlternative THEN skippingAlternative ← TRUE
ELSE inAlternative ← TRUE;
};
showObjectProc: PressReader.ShowObjectProc = {
nTrajectories: INT ← 0;
CurveFlatten: PROCEDURE [curve: CGCubic.Bezier] = {
c1, c2: CGCubic.Bezier;
IF CGCubic.Flat[curve, 1.5] THEN {
x: INT = Real.RoundLI[curve.b3.x];
y: INT = Real.RoundLI[curve.b3.y];
ipMaster.LineTo[IP.int[x], IP.int[y]]
}
ELSE {
[c1, c2] ← CGCubic.Split[curve];
CurveFlatten[c1];
CurveFlatten[c2]; };
}; -- CurveFlatten
moveToProc: PressReader.MoveToProc = {
pX ← entityTrailer.Xe+x;
pY ← entityTrailer.Ye+y;
ipMaster.MoveTo[IP.int[pX], IP.int[pY]];
nTrajectories ← nTrajectories+1;
};
drawToProc: PressReader.DrawToProc = {
xNew: INT ← entityTrailer.Xe+x;
yNew: INT ← entityTrailer.Ye+y;
IF (xNew = pX) AND (yNew = pY) THEN RETURN
ELSE IF yNew = pY THEN ipMaster.LineToX[IP.int[xNew]]
ELSE IF xNew = pX THEN ipMaster.LineToY[IP.int[yNew]]
ELSE ipMaster.LineTo[IP.int[xNew], IP.int[yNew]];
pX ← xNew;
pY ← yNew;
};
drawCurveProc: PressReader.DrawCurveProc = { -- note: Full IP has CurveTo
bezier: CGCubic.Bezier;
bezier ← CGCubic.CoeffsToBezier[CGCubic.Coeffs[
c0: GraphicsBasic.Vec[REAL[pX], REAL[pY]],
c1: GraphicsBasic.Vec[cX, cY],
c2: GraphicsBasic.Vec[bX, bY],
c3: GraphicsBasic.Vec[aX, aY]]];
IF fullInterpress THEN {
x1, y1, x2, y2, x3, y3: INT;
x1 ← Real.RoundLI[bezier.b1.x];
y1 ← Real.RoundLI[bezier.b1.y];
x2 ← Real.RoundLI[bezier.b2.x];
y2 ← Real.RoundLI[bezier.b2.y];
x3 ← Real.RoundLI[bezier.b3.x];
y3 ← Real.RoundLI[bezier.b3.y];
ipMaster.CurveTo[
IP.int[x1], IP.int[y1], IP.int[x2], IP.int[y2], IP.int[x3], IP.int[y3]];
pX ← x3;
pY ← y3;
}
ELSE {
CurveFlatten[bezier];
pX ← Real.RoundLI[bezier.b3.x];
pY ← Real.RoundLI[bezier.b3.y];
};
}; -- drawCurveProc
IF skippingAlternative THEN RETURN;
IF newColor THEN SetColor[];
pressFile.GetObject[[moveToProc, drawToProc, drawCurveProc]];
ipMaster.AppendInteger[nTrajectories];
ipMaster.AppendOp[makeoutline];
ipMaster.AppendOp[maskfill];
}; -- showObjectProc
showRectangleProc: PressReader.ShowRectangleProc = {
IF skippingAlternative THEN RETURN;
IF newColor THEN SetColor[];
ipMaster.MaskRectangle[IP.int[pX+Xe], IP.int[pY+Ye], IP.int[width], IP.int[height]];
};
pressFile.GetCommands[PressReader.CommandProcs[
showCharactersProc: showCharactersProc,
spacingProc: spacingProc,
spaceProc: spaceProc,
positionProc: positionProc,
colorProc: colorProc,
fontProc: fontProc,
alternativeProc: alternativeProc,
showObjectProc: showObjectProc,
showRectangleProc: showRectangleProc
]];
}; -- EntityProc
ipMaster.BeginPage[];
ipMaster.Scale[IP.real[1.0E-5]]; -- scale to Press units (micas)
IF usePriority THEN ipMaster.SetPriorityImportant[TRUE];
pressFile.GetPage[EntityProc];
ipMaster.EndPage[];
IF progressProc # NIL THEN progressProc[page, progressData];
}; -- PageProc
LoadFonts: PROCEDURE = {
fontFile: PressFontReader.Handle ← PressFontReader.FromFile[
"/Indigo/Interpress/Fonts/InterpressFonts.Widths"];
pressFonts: LIST OF PressFontReader.Font ← PressFontReader.ListFonts[fontFile];
fontList: LIST OF REF ANYNIL;
fontName: Rope.ROPE;
f: NAT ← 0;
FontInitProc: PressReader.FontEntryProc = { -- fontDirectoryEntry
pressFont: PressFontReader.Font ← NIL;
fontInfo: PressFontReader.FontInfoRec;
sizeInMicas: INTEGER = IF fontDirectoryEntry.size < 0 THEN -fontDirectoryEntry.size
ELSE Real.RoundI[fontDirectoryEntry.size*(2540.0/72.0)]; -- convert points to micas
FOR list: LIST OF PressFontReader.Font ← pressFonts, list.rest UNTIL list=NIL DO
pressFont ← list.first;
fontInfo ← pressFont.info;
IF Rope.Equal[fontInfo.family, fontDirectoryEntry.family, FALSE]
AND (fontInfo.face = fontDirectoryEntry.face.encoding)
AND ((fontInfo.size = 0) OR (Real.RoundLI[fontInfo.size*1.0E5] = sizeInMicas))
AND ((fontInfo.rotation = fontDirectoryEntry.rotation)) THEN EXIT;
REPEAT
FINISHED => ERROR Error[FontNotFound]; -- couldn't find correct press font
ENDLOOP;
WITH fp: pressFont.private SELECT FROM
widthsOnly => {
font: Font = NEW[FontRec ← [encoding: 0, fontNumber: 0,
family: NIL, faceCode: NIL, sizeInMicas: 0, rotation: 0,
widthX: NIL, widthY: NIL, fixedWidthX: 0, fixedWidthY: 0]];
font.encoding ← fontDirectoryEntry.fontSet*16+fontDirectoryEntry.font;
font.family ← fontInfo.family;
font.faceCode ← Rope.Cat[
SELECT fontDirectoryEntry.face.weight FROM
medium => "M", bold => "B", light => "L", ENDCASE => ERROR,
SELECT fontDirectoryEntry.face.slope FROM
regular => "R", italic => "I", ENDCASE => ERROR,
SELECT fontDirectoryEntry.face.expansion FROM
regular => "R", condensed => "C", expanded => "E", ENDCASE => ERROR];
font.sizeInMicas ← sizeInMicas;
font.rotation ← fontDirectoryEntry.rotation;
IF fontInfo.rotation#0 THEN ERROR; -- worry about this later ...
IF fp.widthSeg.XWidthFixed THEN font.fixedWidthX ← fp.xWidthDesc[0]
ELSE {
widthX: REF WidthArray = NEW[WidthArray ← ALL[0]];
FOR c: CHAR IN[fontInfo.bc..fontInfo.ec] DO
w: INTEGER = LOOPHOLE[fp.xWidthDesc[c-fontInfo.bc]];
IF w#FIRST[INTEGER] THEN widthX[c] ← w;
ENDLOOP;
font.widthX ← widthX;
};
IF fp.widthSeg.YWidthFixed THEN font.fixedWidthY ← fp.yWidthDesc[0]
ELSE {
widthY: REF WidthArray = NEW[WidthArray ← ALL[0]];
FOR c: CHAR IN[fontInfo.bc..fontInfo.ec] DO
w: INTEGER = LOOPHOLE[fp.yWidthDesc[c-fontInfo.bc]];
IF w#FIRST[INTEGER] THEN widthY[c] ← w;
ENDLOOP;
font.widthY ← widthY;
};
IF fontInfo.size=0 THEN { -- must scale widths
s: REAL = sizeInMicas/1000.0; -- scaling factor
widthX: REF WidthArray = font.widthX;
widthY: REF WidthArray = font.widthY;
IF widthX=NIL THEN font.fixedWidthX ← Real.RoundI[s*font.fixedWidthX]
ELSE FOR c: CHAR IN CHAR DO w: INTEGER = widthX[c];
IF w#0 THEN widthX[c] ← Real.RoundI[s*w] ENDLOOP;
IF widthY=NIL THEN font.fixedWidthY ← Real.RoundI[s*font.fixedWidthY]
ELSE FOR c: CHAR IN CHAR DO w: INTEGER = widthY[c];
IF w#0 THEN widthY[c] ← Real.RoundI[s*w] ENDLOOP;
};
fontList ← List.Cons[font, fontList];
nFonts ← nFonts+1;
};
ENDCASE => ERROR;
}; -- FontInitProc
FontCompare: List.CompareProc = CHECKED {
font2: Font ← NARROW[ref2, Font];
WITH ref1 SELECT FROM
font1: Font =>
IF font1.encoding > font2.encoding THEN RETURN [greater]
ELSE IF font1.encoding < font2.encoding THEN RETURN [less]
ELSE RETURN [equal];
ENDCASE => ERROR;
}; -- FontCompare
pressFile.GetFonts[FontInitProc];
IF nFonts # 0 THEN {
fontList ← List.Sort[fontList, FontCompare];
fonts ← NEW[Fonts[nFonts+1]];
tooManyFontsForFrame ← (nFonts > IPLimits.topFrameSize);
WHILE fontList # NIL DO
font: Font = NARROW[fontList.first];
fonts[f] ← font; font.fontNumber ← f;
fontName ← Rope.Cat["Xerox/PressFonts/", fonts[f].family, "-", fonts[f].faceCode];
ipMaster.SetUpFont[
fontNumber: f,
name: fontName,
scale: IP.real[fonts[f].sizeInMicas],
rotation: IP.real[fonts[f].rotation/60.0], -- minutes to degrees
putInFrame: (NOT tooManyFontsForFrame)];
fontList ← fontList.rest;
f ← f+1;
ENDLOOP;
IF tooManyFontsForFrame THEN {
ipMaster.MakeVec[nFonts];
ipMaster.AppendInteger[0];
ipMaster.AppendOp[fset];
};
};
fontFile.Close[];
}; -- LoadFonts
ipMaster.BeginPreamble[];
LoadFonts[];
ipMaster.EndPreamble[];
IF progressProc # NIL THEN progressProc[preamble, progressData];
pressFile.GetParts[partNumber: 0, pageProc: PageProc, fontDirectoryProc: NIL];
ipMaster.EndMaster[];
pressFile.ClosePressFile[];
IF progressProc # NIL THEN progressProc[document, progressData];
}; -- ConvertPressToInterpress
Error: PUBLIC ERROR [errorCode: ErrorCode] = CODE;
END.
Change Log
Created by Shore; September 16, 1982 3:21 pm
Changed by Shore; September 22, 1982 10:33 am
Added ProgressProc
Changed by Shore; September 26, 1982 2:54 pm
converted to new operator interface and added usePriority stuff
Changed by Shore; October 4, 1982 9:40 pm
use PressFontReader.ListFonts instead of EnumerateFonts and VisitFontProc
Changed by Shore; October 14, 1982 4:49 pm
changes for Cedar 3.4 (List.Compare stuff)
Changed by Shore; November 16, 1982 1:08 pm
converted to Cedar.Style and added node formats
Changed by Shore; January 30, 1983 1:11 pm
fixed bug in SHOWing the null (empty) string and runs of blanks
Changed by Wyatt; March 1, 1983 5:05 pm
changed CurveFlatten to round coordinates to nearest mica
Changed by Wyatt; March 2, 1983 10:55 am
added fullInterpress parameter; generate CurveTo's if fullInterpress is true
Changed by Wyatt; March 2, 1983 3:42 pm
get InterpressFonts.Widths from local file (included in PressIP.df)
Changed by Wyatt; March 3, 1983 2:37 pm
changed method of comparing font sizes in font directory lookup
Changed by Wyatt; March 16, 1983 10:17 am
get InterpressFonts.Widths from /Indigo/Interpress/Fonts/InterpressFonts.Widths
Changed by Wyatt; April 5, 1983 4:19 pm
rewrote much of this module to simplify it