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
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.