PressConvertersCommand.mesa
Copyright Ó 1984, 1985, 1986, 1990, 1992 by Xerox Corporation. All rights reserved.
Michael Plass, November 2, 1990 1:14 pm PST
Tim Diebert: February 18, 1986 10:36:06 am PST
Pier, September 21, 1987 5:29:33 pm PDT
Eric Nickell February 19, 1986 2:56:26 pm PST
Doug Wyatt, July 22, 1986 6:28:45 pm PDT
Maureen Stone, January 8, 1988 5:21:44 pm PST
Jean-Marc Frailong January 20, 1988 12:18:56 pm PST
Bloomenthal, July 10, 1992 1:19 pm PDT
Beretta:PARC:Xerox (8*923-4484) August 31, 1989 4:39:01 pm PDT
Willie-s, July 22, 1992 12:35 pm PDT
DIRECTORY Commander, Convert, FileNames, FS, Imager, ImagerError, ImagerFontFilter, ImagerInterpress, ImagerPress, InterpressInterpreter, IO, PressConverters, Process, Rope, ShowPress;
PressConvertersCommand: CEDAR PROGRAM
IMPORTS Commander, Convert, FileNames, FS, Imager, ImagerError, ImagerFontFilter, ImagerInterpress, ImagerPress, InterpressInterpreter, IO, Process, Rope, ShowPress
EXPORTS PressConverters
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
Types and constants
ActionProc: TYPE ~ PressConverters.ActionProc;
ProgressProc: TYPE ~ PressConverters.ProgressProc;
inch: REAL = 0.0254; -- inches->meters conversion factor
ravenPPI: REAL = 300.0; -- pixels per inch on a Raven printer for compression
ravenPPM: REAL = ravenPPI/inch; -- pixels per meters on a Raven printer for compression
defaultPageWidth: REAL ¬ 8.5*inch; -- for normal sized paper
defaultPageHeight: REAL ¬ 11*inch; -- for normal sized paper
defaultAISPixelsPerInch: REAL = 72.0; -- for AIS files
aisMargin: REAL ¬ 0.25*inch; -- offset of AIS images on regular-sized paper
headerSampled: ROPE ¬ "Interpress/Xerox/3.0 "; -- IP header for sampled images
aisCaptionFont: ROPE ¬ "xerox/pressfonts/helvetica-mir"; -- to put caption in AIS files
aisCaptionLoc: Imager.VEC ¬ [72, 9]; -- where the caption should be in AIS files
xcFontBase: Rope.ROPE ¬ "Xerox/xc1-2-2/"; -- prefix to be used for Xerox product fonts
Client interface to Interpress files
PressToInterpress: PUBLIC PROC [inputName: Rope.ROPE, interpress: ImagerInterpress.Ref, beginPage, endPage: ProgressProc, msg: IO.STREAM, useXCFonts: BOOL, verbose: BOOL] RETURNS [failed: BOOL ¬ FALSE] ~ {
Convert press file to IP file. Verbose=TRUE means log font substitutions. Print various feedbacks onto msg (don't print anything if msg is NIL). Supports any IP master version. pageWidth and pageHeight indicate page size in meters (IP conventions). The IP master is not closed on completion.
showPress: ShowPress.Handle = ShowPress.Open[FileNames.ResolveRelativePath[inputName]];
FOR i: INT IN [1..showPress.lastPart) DO
Paint: PROC [context: Imager.Context] ~ {
Process.CheckForAbort[];
failed ¬ beginPage[i, showPress.lastPart-1];
IF failed THEN RETURN;
IF useXCFonts THEN context ¬ ImagerFontFilter.FilterFonts[context, xc1Map, msg, verbose];
Imager.SetPriorityImportant[context, TRUE];
ShowPress.DrawPressPage[context: context, show: showPress, pageNumber: i];
Process.CheckForAbort[];
failed ¬ endPage[i, showPress.lastPart-1];
};
ImagerInterpress.DoPage[self: interpress, action: Paint, scale: 1.0E-5];
IF failed THEN EXIT;
ENDLOOP;
};
Client interface from Interpress files
IPReadError: PUBLIC ERROR [class: INT, code: ATOM, explanation: Rope.ROPE] ~ CODE;
Raised in all procs that read IP masters and have no message stream when the error is not trivial (# classMasterWarning, classAppearanceWarning, classComment)
IPReadLog: PROC [msg: IO.STREAM, class: INT, code: ATOM, explanation: ROPE] ~ {
Log the error in clear if msg stream is present otherwise convert into an error.
IF msg=NIL THEN {
SELECT class FROM
InterpressInterpreter.classMasterError, InterpressInterpreter.classAppearanceError => ERROR IPReadError[class, code, explanation];
InterpressInterpreter.classMasterWarning, InterpressInterpreter.classAppearanceWarning, InterpressInterpreter.classComment => NULL; -- ignore those
ENDCASE => ERROR IPReadError[class, code, explanation];
}
ELSE {
msg.PutRope[
SELECT class FROM
InterpressInterpreter.classMasterError => "Master Error: ",
InterpressInterpreter.classMasterWarning => "Master Warning: ",
InterpressInterpreter.classAppearanceError => "Appearance Error: ",
InterpressInterpreter.classAppearanceWarning => "Appearance Warning: ",
InterpressInterpreter.classComment => "Comment: ",
ENDCASE => Rope.Cat["Class ", Convert.RopeFromInt[class], " Error: "]
];
msg.PutRope[explanation];
msg.PutRope[" . . . "];
};
};
InterpressToPress: PUBLIC PROC [inputName: Rope.ROPE, context: Imager.Context, beginPage, endPage: ProgressProc, msg: IO.STREAM] RETURNS [failed: BOOL ¬ FALSE] ~ {
Convert IP file to press file described by an Imager context (obtained through ImagerPress.SimpleCreate). Errors are logged on msg if present, otherwise they are not caught. Return TRUE if anything went wrong. The press file is not terminated on exit, so that IP masters may be concatenated into a single press file.
Log: InterpressInterpreter.LogProc ~ {
IPReadLog[msg, class, ImagerError.AtomFromErrorCode[code], explanation];
};
input: InterpressInterpreter.Master ¬ InterpressInterpreter.Open[FileNames.ResolveRelativePath[inputName], Log];
FOR i: INT IN [1..input.pages] DO
Process.CheckForAbort[];
failed ¬ beginPage[i, input.pages];
IF failed THEN EXIT;
InterpressInterpreter.DoPage[master: input, page: i, context: context, log: Log];
Process.CheckForAbort[];
failed ¬ endPage[i, input.pages];
IF i # input.pages THEN ImagerPress.NewPage[context];
ENDLOOP;
InterpressInterpreter.Close[input];
};
XC Font translation
CH: PROC [char: CHAR] RETURNS [WORD] ~ INLINE {RETURN [ORD[char]]};
XC: PROC [set: [0..256), code: [0..256)] RETURNS [WORD] ~ {RETURN [set*256+code]};
C1: PROC [c: CHAR, set: [0..256), code: [0..256)] RETURNS [ImagerFontFilter.CharRangeMap] ~ {
RETURN [[bc: CH[c], ec: CH[c], newbc: XC[set, code]]]
};
classicModernEtAl: LIST OF ROPE ¬ LIST["Classic", "Modern"];
timesRomanEtAl: LIST OF LIST OF ROPE ¬ LIST[
LIST["TimesRoman", "Classic"],
LIST["Helvetica", "Modern"],
LIST["Gacha", "XeroxBook"],
LIST["Tioga", "Classic"],
LIST["Laurel", "Classic"]];
mrrEtAl: LIST OF ROPE ¬ LIST["-mrr", "-mir-italic", "-bir-bold-italic", "-brr-bold"];
alphaMap: ImagerFontFilter.CharacterCodeMap ~ LIST [
[bc: CH[' ], ec: CH['~], newbc: CH[' ]]
];
mathMap: ImagerFontFilter.CharacterCodeMap ¬ LIST [
C1['©, 0, 323B],
C1['®, 0, 322B]
];
oisMap: ImagerFontFilter.CharacterCodeMap ¬ LIST [
[bc: CH['a], ec: CH['~], newbc: CH['a]],
[bc: CH['.], ec: CH[']], newbc: CH['.]],
[bc: CH['%], ec: CH[',], newbc: CH['%]],
[bc: CH['-], ec: CH['-], newbc: XC[357B, 42B]],
[bc: CH[' ], ec: CH['!], newbc: CH[' ]],
[bc: CH['\"], ec: CH['\"], newbc: XC[0, 271B]],
[bc: CH['#], ec: CH['#], newbc: CH['#]],
[bc: CH['$], ec: CH['$], newbc: XC[0, 244B]],
[bc: CH['^], ec: CH['^], newbc: XC[0, 255B]],
[bc: CH['←], ec: CH['←], newbc: XC[0, 254B]],
C1['\030, 357B, 45B],
C1['\267, 357B, 146B],
C1['\265, 41B, 172B],
C1['\140, 0, 140B],
C1[', 357B, 064B],
C1[', 357B, 065B],
];
xc1Map: ImagerFontFilter.FontMap ¬ MakeXC1map[];
This is what all this section is about...
MakeXC1map: PROC RETURNS [f: ImagerFontFilter.FontMap] ~ {
Enter: PROC [e: ImagerFontFilter.FontMapEntry] ~ {f ¬ CONS[e, f]};
FOR family: LIST OF ROPE ¬ classicModernEtAl, family.rest UNTIL family = NIL DO
FOR face: LIST OF ROPE ¬ mrrEtAl, face.rest UNTIL face = NIL DO
Enter[[
inputName: Rope.Cat["Xerox/Pressfonts/", family.first, face.first.Substr[0, 4]],
output: LIST[[newName: Rope.Cat[xcFontBase, family.first, face.first.Substr[4]], charMap: oisMap]]
]];
ENDLOOP;
ENDLOOP;
FOR family: LIST OF LIST OF ROPE ¬ timesRomanEtAl, family.rest UNTIL family = NIL DO
FOR face: LIST OF ROPE ¬ mrrEtAl, face.rest UNTIL face = NIL DO
Enter[[
inputName: Rope.Cat["Xerox/Pressfonts/", family.first.first, face.first.Substr[0, 4]],
output: LIST[[newName: Rope.Cat[xcFontBase, family.first.rest.first, face.first.Substr[4]], charMap: oisMap]],
warn: TRUE
]];
ENDLOOP;
ENDLOOP;
Enter[[
inputName: "Xerox/Pressfonts/Logo-mrr",
output: LIST[[newName: Rope.Concat[xcFontBase, "Logotypes-Xerox"], charMap: alphaMap]]
]];
Enter[[
inputName: "Xerox/Pressfonts/Math-mrr",
output: LIST[[newName: Rope.Concat[xcFontBase, "Modern"], charMap: mathMap]]
]];
Enter[[
inputName: "Xerox/Pressfonts/Math-mir",
output: LIST[[newName: Rope.Concat[xcFontBase, "Modern-italic"], charMap: mathMap]]
]];
};
Command level
PressToInterpressAction: PUBLIC ActionProc ~ {
BeginPage: ProgressProc ~ {cmd.out.PutF1["[%g", IO.int[pageNumber]]};
EndPage: ProgressProc ~ {cmd.out.PutRope["] "]};
version: ROPE = GetCmdToken[cmds];
verbose: ROPE = GetCmdToken[cmds];
header: ROPE = IF Rope.Size[version] = 3 AND Rope.Fetch[version, 1] = '. THEN Rope.Cat["Interpress/Xerox/", version, " "] ELSE NIL;
output: ImagerInterpress.Ref ¬ ImagerInterpress.Create[outputName, header];
xc: BOOL ¬ Rope.Size[version] = 3 AND Rope.Fetch[version, 0] < '3;
[] ¬ PressToInterpress[inputName, output, BeginPage, EndPage, cmd.out, xc, verbose.Equal["verbose", FALSE]];
ImagerInterpress.Close[output];
};
InterpressToPressAction: PUBLIC ActionProc ~ {
BeginPage: ProgressProc ~ {cmd.out.PutF1["[%g", IO.int[pageNumber]]};
EndPage: ProgressProc ~ {cmd.out.PutRope["] "]};
context: Imager.Context ~ ImagerPress.SimpleCreate[fileName: outputName, printerType: press];
[] ¬ InterpressToPress[inputName, context, BeginPage, EndPage, cmd.out];
ImagerPress.Close[context];
};
FindFullName: PROC [inputName: ROPE] RETURNS [ROPE] ~ {
fullFName: ROPE ¬ NIL;
fullFName ¬ FS.FileInfo[inputName].fullFName;
RETURN [fullFName]
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE ¬ NIL] = {
CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← OR char = '[ OR char = '] THEN RETURN [break];
IF char = ' OR char = '\t OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
rope ¬ stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
GetFileNameToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE ¬ NIL] = {
FileNameTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← THEN RETURN [break];
IF char = ' OR char = '\t OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
rope ¬ stream.GetTokenRope[FileNameTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
RealFromRope: PROC [rope: ROPE] RETURNS [real: REAL] = {
oops: BOOL ¬ FALSE;
real ¬ Convert.RealFromRope[rope ! Convert.Error => {oops ¬ TRUE; CONTINUE}];
IF oops THEN {oops ¬ FALSE; real ¬ Convert.IntFromRope[rope ! Convert.Error => {oops ¬ TRUE; CONTINUE}]};
IF oops THEN Complain[Rope.Concat["Number expected: ", rope]];
};
Complain: PUBLIC ERROR [complaint: ROPE] ~ CODE;
ForceLower: PROC [old: CHAR] RETURNS [CHAR] ~ {
RETURN [IF old IN ['A..'Z] THEN old+('a-'A) ELSE old]
};
MakeOutputName: PROC [inputName: ROPE, doc: ROPE] RETURNS [ROPE] ~ {
Relying on doc, and having the install files register commands seems unsafe. Jules
start: INT ¬ Rope.Index[s1: doc, s2: " to "]+4;
end: INT ¬ Rope.SkipTo[s: doc, pos: start, skip: " \n\t"];
cp: FS.ComponentPositions;
isAIS: BOOL ¬ Rope.Equal[Rope.Substr[doc, start, end-start], "ais", FALSE];
[inputName, cp] ¬ FS.ExpandName[inputName];
RETURN [Rope.Cat[
Rope.Translate[inputName, cp.base.start, cp.base.length, ForceLower],
IF isAIS THEN NIL ELSE ".",
IF isAIS THEN NIL ELSE Rope.Translate[doc, start, end-start, ForceLower]
]]
};
Command: PUBLIC Commander.CommandProc ~ {
refAction: REF ActionProc ~ NARROW[cmd.procData.clientData];
stream: IO.STREAM ¬ IO.RIS[cmd.commandLine];
firstToken: ROPE ¬ GetFileNameToken[stream];
quiet: BOOL ¬ Rope.Equal[firstToken, "-q", FALSE];
outputName: ROPE ¬
FileNames.ResolveRelativePath[IF quiet THEN GetFileNameToken[stream] ELSE firstToken];
secondTokenIndex: INT ¬ IO.GetIndex[stream];
gets: ROPE ¬ GetFileNameToken[stream];
inputName: ROPE ¬ NIL;
IF NOT gets.Equal["←"] THEN {
inputName ¬ outputName;
outputName ¬ NIL;
stream.SetIndex[secondTokenIndex];
}
ELSE {inputName ¬ FileNames.ResolveRelativePath[GetFileNameToken[stream]]};
IF inputName = NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc];
inputName ¬ FindFullName[inputName ! FS.Error => {
IF error.group = user THEN {result ¬ $Failure; msg ¬ error.explanation; GOTO Quit}
}];
IF outputName = NIL THEN {
outputName ¬ MakeOutputName[inputName, cmd.procData.doc];
};
cmd.out.PutRope["Reading "];
cmd.out.PutRope[inputName];
cmd.out.PutRope[" . . . "];
IF quiet THEN cmd.commandLine ¬ NIL;
refAction­[inputName, outputName, cmd, stream !
Complain => {result ¬ $Failure; msg ¬ complaint; GOTO Quit};
FS.Error => {
IF error.group = user THEN {result ¬ $Failure; msg ¬ error.explanation; GOTO Quit}
}
];
outputName ¬ FindFullName[outputName ! FS.Error => {
outputName ¬ "Output file(s)"; CONTINUE};
];
cmd.out.PutRope[outputName];
cmd.out.PutRope[" written.\n"];
EXITS Quit => NULL
};
Commands
Commander.Register["PressToInterpress", Command, "Convert Press file to Interpress (output ← input [version])\n", NEW[ActionProc ¬ PressToInterpressAction]];
Commander.Register["InterpressToPress", Command, "Convert Interpress file to Press (output ← input)\n", NEW[ActionProc ¬ InterpressToPressAction]];
END.