PrintFileConvertImpl.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, September 22, 1986 11:27:42 am PDT
Tim Diebert: February 18, 1986 10:36:06 am PST
Pier, December 17, 1985 10:21:47 am PST
Eric Nickell February 19, 1986 2:56:26 pm PST
Doug Wyatt, July 22, 1986 6:28:45 pm PDT
DIRECTORY
Atom USING [GetPName, MakeAtom],
Commander USING [CommandProc, Handle, Register],
Convert USING [AtomFromRope, Error, IntFromRope, RealFromRope, RopeFromInt],
FS USING [ComponentPositions, Error, ExpandName, FileInfo, StreamOpen],
Imager USING [Context, DoSave, MaskRectangle, metersPerInch, PixelArray, Rectangle, RotateT, Scale2T, ScaleT, SetFont, SetPriorityImportant, SetSampledColor, SetXY, ShowRope, TranslateT, VEC],
ImagerBrick USING [Brick, BrickRep],
ImagerColorOperator USING [GrayLinearColorModel, RGBLinearColorModel],
ImagerFont USING [Find, Scale],
ImagerFontFilter USING [CharacterCodeMap, CharRangeMap, FilterFonts, FontMap, FontMapEntry],
ImagerInterpress USING [Close, Create, DeclarePixelArray, DoPage, Ref],
ImagerPD USING [Close, CreateFromParameters, DoPage, PD, SetHalftoneProperties, Toner, Toners],
ImagerPixelArray USING [FromAIS, Join3AIS, MaxSampleValue],
ImagerPixelMap USING [Create, Fill, PixelMap],
ImagerPress USING [Close, NewPage, PrinterType, SimpleCreate],
ImagerSmooth USING [Create, LikeScreen, SetComponent],
ImagerToJaM USING [Close, Create],
ImagerTransformation USING [TransformRectangle],
Interpress USING [classAppearanceError, classAppearanceWarning, classComment, classMasterError, classMasterWarning, DoPage, LogProc, Master, Open],
IO USING [CharClass, EndOf, EndOfStream, GetBlock, GetIndex, GetLength, GetLineRope, GetTokenRope, int, PutChar, PutF, PutFR, PutRope, refAny, RIS, rope, SetIndex, STREAM],
PixelMapOps USING [StoreAIS],
PrintFileConvert USING [PDParams, ProgressProc],
Process USING [CheckForAbort],
Real USING [Round, RoundLI],
Rope USING [Cat, Concat, Equal, Fetch, Find, FromRefText, Index, Length, ROPE, Size, Substr, Translate, TranslatorType],
RopeFile USING [Create],
RuntimeError USING [UNCAUGHT],
ShowPress USING [DrawPressPage, Handle, Open];
PrintFileConvertImpl: CEDAR PROGRAM
IMPORTS Atom, Commander, Convert, FS, Imager, ImagerColorOperator, ImagerFont, ImagerFontFilter, ImagerInterpress, ImagerPD, ImagerPixelArray, ImagerPixelMap, ImagerPress, ImagerSmooth, ImagerToJaM, ImagerTransformation, Interpress, IO, PixelMapOps, Process, Real, Rope, RopeFile, RuntimeError, ShowPress
EXPORTS PrintFileConvert
~ BEGIN OPEN PrintFileConvert;
ROPE: TYPE ~ Rope.ROPE;
ActionProc: TYPE ~ PROC [inputName: ROPE, outputName: ROPE, cmd: Commander.Handle, cmds: IO.STREAM];
LogError: PROC [msg: IO.STREAM, class: INT, code: ATOM, explanation: ROPE] ~ {
msg.PutRope[
SELECT class FROM
Interpress.classMasterError => "Master Error: ",
Interpress.classMasterWarning => "Master Warning: ",
Interpress.classAppearanceError => "Appearance Error: ",
Interpress.classAppearanceWarning => "Appearance Warning: ",
Interpress.classComment => "Comment: ",
ENDCASE => Rope.Cat["Class ", Convert.RopeFromInt[class], " Error: "]
];
msg.PutRope[explanation];
msg.PutRope[" . . . "];
};
InterpressToAISAction: ActionProc = {
AColor: TYPE = {red, green, blue};
aA: ARRAY AColor OF ATOM = [$Red, $Green, $Blue];
om: Interpress.Master;
sPixelsPerInch, fPixelsPerInch: REAL ← 72.0;
sPixelsPerInchI, fPixelsPerInchI: INT;
pixelMap: ImagerPixelMap.PixelMap;
context: Imager.Context;
gray: BOOLFALSE;
complaint: ROPE;
Log: Interpress.LogProc ~ { LogError[cmd.out, class, code, explanation] };
UNTIL IO.EndOf[self: cmds] DO {
token: ROPE ~ GetCmdToken[cmds];
IF token=NIL THEN LOOP;
SELECT TRUE FROM
Rope.Equal[token, "gray", FALSE] => gray ← TRUE;
Rope.Equal[token, "ppi:", FALSE] => sPixelsPerInch ← fPixelsPerInch ← Convert.RealFromRope[r: GetCmdToken[cmds] ! Convert.Error => {cmd.out.PutRope["\nIllegal value for ppi.\n"]; GOTO Fail}];
Rope.Equal[token, "sppi:", FALSE] => sPixelsPerInch ← Convert.RealFromRope[r: GetCmdToken[cmds] ! Convert.Error => {complaint ← "\nIllegal value for sppi.\n"; GOTO Fail}];
Rope.Equal[token, "fppi:", FALSE] => fPixelsPerInch ← Convert.RealFromRope[r: GetCmdToken[cmds] ! Convert.Error => {complaint ← "\nIllegal value for fppi.\n"; GOTO Fail}];
ENDCASE => {complaint ← Rope.Cat["\nUnrecognized token: ", token, "\n"]; GOTO Fail};
EXITS Fail => Complain[complaint]
} ENDLOOP;
om ← Interpress.Open[inputName, Log];
sPixelsPerInchI ← Real.RoundLI[sPixelsPerInch];
fPixelsPerInchI ← Real.RoundLI[fPixelsPerInch];
pixelMap ← ImagerPixelMap.Create[3, [0, 0, 11*sPixelsPerInchI, (85*fPixelsPerInchI)/10]];
context ← ImagerSmooth.Create[pixelMap: pixelMap, component: $Intensity, viewToPixel: ImagerSmooth.LikeScreen[11*sPixelsPerInchI], initialScale: fPixelsPerInch/0.0254, change: NIL, changeData: NIL, cacheFonts: TRUE, surfaceUnitsPerPixel: 5];
IF gray THEN { -- Intensity map
Process.CheckForAbort[];
cmd.out.PutF["[%g", IO.int[1]];
ImagerPixelMap.Fill[dest: pixelMap, area: [0, 0, 10000, 10000], value: 377B];
Interpress.DoPage[master: om, page: 1, context: context, log: Log];
PixelMapOps.StoreAIS[Rope.Cat[outputName, ".ais"], [pixelMap, FALSE, NIL]];
cmd.out.PutRope["] "];
}
ELSE FOR i: AColor IN AColor DO
Process.CheckForAbort[];
cmd.out.PutF["[%g", IO.refAny[aA[i]]];
ImagerPixelMap.Fill[dest: pixelMap, area: [0, 0, 10000, 10000], value: 377B];
ImagerSmooth.SetComponent[context, aA[i]];
Interpress.DoPage[master: om, page: 1, context: context, log: Log];
PixelMapOps.StoreAIS[Rope.Cat[outputName, "-", Atom.GetPName[aA[i]], ".ais"], [pixelMap, FALSE, NIL]];
cmd.out.PutRope["] "];
ENDLOOP;
};
PressToInterpressAction: ActionProc ~ {
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;
showPress: ShowPress.Handle ~ ShowPress.Open[inputName];
interpress: ImagerInterpress.Ref ← ImagerInterpress.Create[outputName, header];
xc: BOOL ← Rope.Size[version] = 3 AND Rope.Fetch[version, 0] < '3;
FOR i: INT IN [1..showPress.lastPart) DO
Paint: PROC [context: Imager.Context] ~ {
cmd.out.PutF["[%g", IO.int[i]];
IF xc THEN context ← FontTranslator[context, version, cmd, verbose.Equal["verbose", FALSE]];
Imager.SetPriorityImportant[context, TRUE];
ShowPress.DrawPressPage[context: context, show: showPress, pageNumber: i];
cmd.out.PutRope["] "];
};
Process.CheckForAbort[];
ImagerInterpress.DoPage[self: interpress, action: Paint, scale: 1.0E-5];
ENDLOOP;
ImagerInterpress.Close[interpress];
};
inch: REAL ~ 0.0254;
headerSampled: ROPE ← "Interpress/Xerox/3.0 ";
aisMargin: REAL ← 0.25*inch;
pageWidth: REAL ← 8.5*inch;
pageHeight: REAL ← 11*inch;
captionFont: ROPE ← "xerox/pressfonts/helvetica-mir";
captionLoc: Imager.VEC ~ [72, 9];
FileChoice: PROC [r: Rope.ROPE, a: ARRAY [0..3) OF Rope.ROPE]
RETURNS [result: Rope.ROPENIL] ~ {
FOR i: NAT IN [0..3) DO
IF a[i] # NIL THEN {
name: ROPE ~ Rope.Cat[r, "-", a[i], ".ais"];
result ← FS.FileInfo[name ! FS.Error => {IF error.code = $unknownFile THEN CONTINUE}].fullFName;
IF result# NIL THEN RETURN;
};
ENDLOOP;
};
GetColorNames: PROC [name: Rope.ROPE] RETURNS [ok: BOOL, red, grn, blu: Rope.ROPE] ~ {
red ← FileChoice[name, ["red", "r", NIL]];
IF red = NIL THEN { ok ← FALSE; RETURN};
grn ← FileChoice[name, ["grn", "green", "g"]];
IF grn = NIL THEN { ok ← FALSE; RETURN};
blu ← FileChoice[name, ["blu", "blue", "b"]];
ok ← blu # NIL;
};
ColorAISToInterpressCommand: Commander.CommandProc ~ {
red, grn, blu: ROPE;
interpress: ImagerInterpress.Ref;
pa: Imager.PixelArray;
maxSample: CARDINAL;
rect: Imager.Rectangle;
scale: REAL;
Paint: PROC [context: Imager.Context] ~ {
Caption: PROC ~ {
Imager.ScaleT[context, inch/72];
Imager.SetFont[context, ImagerFont.Scale[ImagerFont.Find[captionFont], 9]];
Imager.SetXY[context, [72, 9]];
Imager.ShowRope[context, cmd.commandLine];
};
Imager.SetPriorityImportant[context, TRUE];
Imager.DoSave[context, Caption];
Imager.TranslateT[context, [pageWidth*0.5, pageHeight*0.5]];
Imager.ScaleT[context, scale];
Imager.TranslateT[context, [-(rect.x+rect.w*0.5), -(rect.y+rect.h*0.5)]];
Imager.SetSampledColor[context: context, pa: pa, m: NIL, colorOperator: ImagerColorOperator.RGBLinearColorModel[maxSample]];
Imager.MaskRectangle[context, rect];
};
stream: IO.STREAMIO.RIS[cmd.commandLine];
outputName: ROPE ← GetCmdToken[stream];
secondTokenIndex: INTIO.GetIndex[stream];
gets: ROPE ← GetCmdToken[stream];
ok: BOOLFALSE;
inputName: ROPENIL;
IF NOT gets.Equal["←"] THEN {
inputName ← outputName;
outputName ← NIL;
stream.SetIndex[secondTokenIndex];
}
ELSE {inputName ← GetCmdToken[stream]};
IF inputName = NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc];
[ok, red, grn, blu] ← GetColorNames[inputName ! FS.Error => {
IF error.group = user THEN {result ← $Failure; msg ← error.explanation; GOTO Quit}
}];
IF NOT ok THEN RETURN[result: $Failure, msg: "Could not find one or more of the input files\n"];
IF outputName = NIL THEN {
outputName ← MakeOutputName[inputName, cmd.procData.doc];
};
cmd.out.PutF["Reading\n %g\n %g\n %g . . . ", IO.rope[red], IO.rope[grn], IO.rope[blu]];
pa ← ImagerPixelArray.Join3AIS[red, grn, blu];
maxSample ← ImagerPixelArray.MaxSampleValue[pa, 0];
rect ← ImagerTransformation.TransformRectangle[pa.m, [0, 0, pa.sSize, pa.fSize]];
scale ← MIN[(pageWidth-2*aisMargin)/rect.w, (pageHeight-2*aisMargin)/rect.h];
interpress ← ImagerInterpress.Create[outputName, headerSampled];
ImagerInterpress.DeclarePixelArray[interpress, pa];
ImagerInterpress.DoPage[self: interpress, action: Paint, scale: 1.0];
ImagerInterpress.Close[interpress];
outputName ← FindFullName[outputName];
cmd.out.PutRope["\n "];
cmd.out.PutRope[outputName];
cmd.out.PutRope[" written.\n"];
EXITS Quit => NULL
};
AISToInterpressAction: ActionProc ~ {
interpress: ImagerInterpress.Ref ← ImagerInterpress.Create[outputName, headerSampled];
pa: Imager.PixelArray ← ImagerPixelArray.FromAIS[inputName];
maxSample: CARDINAL ~ ImagerPixelArray.MaxSampleValue[pa, 0];
rect: Imager.Rectangle ← ImagerTransformation.TransformRectangle[pa.m, [0, 0, pa.sSize, pa.fSize]];
scale: REALMIN[(pageWidth-2*aisMargin)/rect.w, (pageHeight-2*aisMargin)/rect.h];
Paint: PROC [context: Imager.Context] ~ {
Caption: PROC ~ {
Imager.ScaleT[context, inch/72];
Imager.SetFont[context, ImagerFont.Scale[ImagerFont.Find[captionFont], 9]];
Imager.SetXY[context, [72, 9]];
Imager.ShowRope[context, cmd.commandLine];
};
Imager.SetPriorityImportant[context, TRUE];
Imager.DoSave[context, Caption];
Imager.TranslateT[context, [pageWidth*0.5, pageHeight*0.5]];
Imager.ScaleT[context, scale];
Imager.TranslateT[context, [-(rect.x+rect.w*0.5), -(rect.y+rect.h*0.5)]];
Imager.SetSampledColor[context: context, pa: pa, m: NIL, colorOperator: ImagerColorOperator.GrayLinearColorModel[maxSample, 0, maxSample]];
Imager.MaskRectangle[context, rect];
};
cmd.out.PutF["[%g", IO.int[1]];
ImagerInterpress.DeclarePixelArray[interpress, pa];
ImagerInterpress.DoPage[self: interpress, action: Paint, scale: 1.0];
cmd.out.PutRope["] "];
ImagerInterpress.Close[interpress];
};
InterpressToPressAction: ActionProc ~ {
Log: Interpress.LogProc ~ { LogError[cmd.out, class, code, explanation] };
interpress: Interpress.Master ~ Interpress.Open[inputName, Log];
context: Imager.Context ~ ImagerPress.SimpleCreate[fileName: outputName, printerType: press];
FOR i: INT IN [1..interpress.pages] DO
Process.CheckForAbort[];
cmd.out.PutF["[%g", IO.int[i]];
Interpress.DoPage[master: interpress, page: i, context: context, log: Log];
cmd.out.PutRope["] "];
IF i # interpress.pages THEN ImagerPress.NewPage[context];
ENDLOOP;
ImagerPress.Close[context];
};
InterpressToJaMAction: ActionProc ~ {
Log: Interpress.LogProc ~ { LogError[cmd.out, class, code, explanation] };
interpress: Interpress.Master ~ Interpress.Open[inputName, Log];
stream: IO.STREAM ~ FS.StreamOpen[outputName, $create];
context: Imager.Context ~ ImagerToJaM.Create[stream];
stream.PutRope["% Produced from "];
stream.PutRope[inputName];
stream.PutRope["\n"];
FOR i: INT IN [1..interpress.pages] DO
Process.CheckForAbort[];
stream.PutF["%% Page %g\n", IO.int[i]];
Interpress.DoPage[master: interpress, page: i, context: context, log: Log];
ENDLOOP;
ImagerToJaM.Close[context];
};
Rev: PROC [list: ImagerPD.Toners] RETURNS [ImagerPD.Toners] ~ {
l1, l2, l3: ImagerPD.Toners ← NIL;
IF list = NIL THEN RETURN[NIL];
l3 ← list;
UNTIL (l1 ← l3) = NIL DO
l3 ← l3.rest;
l1.rest ← l2;
l2 ← l1;
ENDLOOP;
RETURN[l2];
};
Bound: TYPE ~ RECORD [first, last: INT];
int: Bound ~ [INT.FIRST, INT.LAST];
nat: Bound ~ [NAT.FIRST, NAT.LAST];
card: Bound ~ [CARDINAL.FIRST, CARDINAL.LAST];
RealToNum: PROC [real: REAL, bounds: Bound ← int, name: ROPENIL] RETURNS [number: INT ← 0] ~ {
IF name=NIL THEN name ← "Value";
number ← Real.Round[real ! RuntimeError.UNCAUGHT => CONTINUE];
IF real#number THEN Complain[IO.PutFR[format: "%g (%g) should be integral.", v1: [rope [name]], v2: [real [real]]]];
IF number NOT IN [bounds.first .. bounds.last] THEN Complain[IO.PutFR[format: "Value (%g) should be in range [%g .. %g]", v1: [rope [name]], v2: [integer [bounds.first]], v3: [integer [bounds.last]]]];
};
xStar: ROPE ~ FS.ExpandName["*"].fullFName;
regDir: ROPE ~ Rope.Substr[xStar, 0, Rope.Size[xStar]-1];
wDirList: LIST OF ROPELIST[NIL, regDir];
FileContents: PROC [base, ext: ROPE] RETURNS [ROPE] ~ {
FOR each: LIST OF ROPE ← wDirList, each.rest UNTIL each = NIL DO
name: ROPE ~ FS.ExpandName[name: Rope.Cat[base, ext], wDir: each.first].fullFName;
RETURN [RopeFile.Create[name: name, raw: FALSE ! FS.Error => {IF error.group = user THEN CONTINUE}]];
ENDLOOP;
Complain[IO.PutFR[format: "Device type %g undefined.", v1: [rope [base]]]];
};
Specs: TYPE ~ RECORD [
params: PDParams, -- PD parameters
sx, sy: REAL ← 1.0, -- scale
rotateDegrees: REAL ← 1.0, -- rotate
tx, ty: REAL ← 0.0, -- translate
skipPages: INT ← 0,
nPages: INTINT.LAST
];
GetSpecs: PROC [deviceCodeRope: ROPENIL, deviceSpecRope: ROPENIL] RETURNS [Specs] ~ {
ToLowerCase: Rope.TranslatorType = {
[old: CHAR] RETURNS [new: CHAR]
RETURN [SELECT old FROM
IN ['A .. 'Z] => old + ('a - 'A),
ENDCASE => old
]
};
Err: PROC ~ {
IF tok#NIL THEN Complain[Rope.Concat["Unknown keyword: ", tok]]
ELSE Complain["Malformed command"];
};
specsFromFile: ROPE ~ FileContents[deviceCodeRope, ".pdDeviceSpec"];
specsRope: ROPE ~ Rope.Cat[specsFromFile, "CommandLineParameters ", deviceSpecRope];
cmds: IO.STREAM ~ IO.RIS[specsRope];
params: PDParams ← [];
tok: ROPENIL;
tx, ty: REAL ← 0.0;
rotateDegrees: REAL ← 0.0;
sx, sy: REAL ← 1.0;
skipPages: INT ← 0;
nPages: INTINT.LAST;
toners: ImagerPD.Toners ← NIL;
tokensSinceLastToner: CARDINAL ← 1;
parsingPDDeviceSpecFile: BOOLEANTRUE;
leftBracket: ATOM ~ Atom.MakeAtom["["];
ParseBrick: PROC ~ {
a: REF ARRAY [0..1000) OF REALNEW[ARRAY [0..1000) OF REAL];
sSize: NAT ← 0;
fSize: NAT ← 0;
phase: NAT ← 0;
toner: ImagerPD.Toner ← black;
n: NAT ← 0;
brick: ImagerBrick.Brick ← NIL;
tok ← GetCmdToken[cmds];
WHILE Rope.Equal[tok, "["] DO
tok ← GetCmdToken[cmds];
WHILE tok # NIL AND NOT Rope.Equal[tok, "]"] DO
real: REAL ~ RealFromRope[tok];
IF real NOT IN [0.0..1.0] THEN Complain["Brick values should be between 0 and 1"];
a[n] ← real;
n ← n + 1;
IF sSize = 0 THEN fSize ← fSize + 1;
tok ← GetCmdToken[cmds];
ENDLOOP;
sSize ← sSize + 1;
IF n MOD fSize # 0 THEN Complain["Malformed array"];
tok ← GetCmdToken[cmds];
ENDLOOP;
IF Rope.Equal[tok, "]"] THEN tok ← GetCmdToken[cmds] ELSE Complain["Malformed array"];
phase ← RealToNum[RealFromRope[tok], card]; tok ← GetCmdToken[cmds];
SELECT TRUE FROM
Rope.Equal[tok, "black", FALSE] => toner ← black;
Rope.Equal[tok, "cyan", FALSE] => toner ← cyan;
Rope.Equal[tok, "magenta", FALSE] => toner ← magenta;
Rope.Equal[tok, "yellow", FALSE] => toner ← yellow;
ENDCASE => Complain[Rope.Cat["Expected toner name, but found \"", tok, "\""]];
tok ← GetCmdToken[cmds];
IF NOT Rope.Equal[tok, "brick", FALSE] THEN Complain["Missing \"brick\" Keyword"];
brick ← NEW[ImagerBrick.BrickRep[n]];
brick.sSize ← sSize;
brick.fSize ← fSize;
brick.phase ← phase;
brick.u ← 0;
brick.v ← 0;
FOR i: NAT IN [0..n) DO brick[i] ← a[i] ENDLOOP;
params.bricks[toner] ← brick;
};
params.ppd ← -1.0;
params.sRes ← params.fRes ← 384;
params.deviceCode ← 15;
params.pageSSize ← 11.0;
params.pageFSize ← 8.5;
UNTIL (tok ← GetCmdToken[cmds]) = NIL DO
atom: ATOM ← Convert.AtomFromRope[Rope.Translate[base: tok, translator: ToLowerCase]];
tokensSinceLastToner ← tokensSinceLastToner + 1;
IF tok.Length[]>1 AND tok.Substr[len: 2].Equal["--"] THEN { --Handle double-dash comments
pos: INT ~ tok.Find[s2: "\n"];
IF pos=-1 THEN {
[] ← IO.GetLineRope[cmds ! IO.EndOfStream => CONTINUE];
LOOP;
}
ELSE atom ← Convert.AtomFromRope[Rope.Translate[base: tok ← Rope.Substr[base: tok, start: pos+1], translator: ToLowerCase]];
};
SELECT atom FROM
leftBracket => ParseBrick[];
$commandlineparameters => parsingPDDeviceSpecFile ← FALSE; --Mostly used to separate potential toner strings from each other if a toner string is the last thing in a pdDeviceSpec file
$black, $cyan, $magenta, $yellow => {
IF tokensSinceLastToner > 1 THEN toners ← NIL;
tokensSinceLastToner ← 0;
toners ← CONS[SELECT atom FROM $black=>black, $cyan=>cyan, $magenta=>magenta, $yellow=>yellow, ENDCASE => ERROR, toners];
};
$leftovers => params.leftovers ← TRUE;
$noleftovers => params.leftovers ← FALSE;
$fonttuning => params.fontTuning ← GetCmdToken[cmds];
$of => {
tok ← GetCmdToken[cmds];
SELECT TRUE FROM
Rope.Equal[tok, "3", FALSE] => {
params.tonerUniverse ← LIST[cyan, magenta, yellow];
};
Rope.Equal[tok, "4", FALSE] => {
params.tonerUniverse ← LIST[black, cyan, magenta, yellow];
};
ENDCASE => Err[];
};
ENDCASE => {
real: REAL ~ RealFromRope[tok];
atom ← Convert.AtomFromRope[Rope.Translate[base: tok ← GetCmdToken[cmds], translator: ToLowerCase]]; --Assign to tok for error reporting
SELECT atom FROM
$ppd => params.ppd ← real;  --<real> ppd
$in => {    --<real> in <real2> in translate
tx ← real;
ty ← RealFromRope[GetCmdToken[cmds]];
Require[cmds, "in", FALSE];
Require[cmds, "translate", FALSE];
};
$rotate => rotateDegrees ← real;    --<real> rotate
$scale => sx ← sy ← real;    --<real> scale
$scalex => sx ← real;    --<real> scaleX
$scaley => sy ← real;    --<real> scaleY
$skippages => skipPages ← RealToNum[real,int,tok]; --<int> skipPages
$npages => nPages ← RealToNum[real,int,tok];  --<int> nPages
$sresolution => params.sRes ← RealToNum[real, card]; --<int> sResolution
$fresolution => params.fRes ← RealToNum[real, card]; --<int> fResolution
$resolution => params.sRes ← params.fRes ← RealToNum[real, card]; --<int> Resolution
$devicecode => params.deviceCode ← RealToNum[real, [0,15]]; --<int> deviceCode
$pagessize => params.pageSSize ← real;  --<real> pageSSize
$pagefsize => params.pageFSize ← real;  --<real> pageFSize
$bandsize => params.bandSize ← RealToNum[real,nat,tok]; --<int> bandSize
$load => params.load ← RealToNum[real,int,tok];  --<int> load
$gamma => params.ucr.blackGamma ← real;  --<real> gamma
$threshold => params.ucr.blackThreshold ← real;  --<real> threshold
$removedfraction => params.ucr.removedFraction ← real; --<real> removedFraction
ENDCASE => Err[];
};
ENDLOOP;
params.toners ← Rev[toners];
RETURN [[params: params, sx: sx, sy: sy, rotateDegrees: rotateDegrees, tx: tx, ty: ty, skipPages: skipPages, nPages: nPages]];
};
IPToPDAction: ActionProc ~ {
deviceCodeRope: ROPE ~ GetCmdToken[cmds];
text: REF TEXT ~ NEW[TEXT[IO.GetLength[cmds]-IO.GetIndex[cmds]]];
nBytesRead: [0..0] ~ IO.GetBlock[self: cmds, block: text]-text.maxLength;
specs: Specs ~ GetSpecs[deviceCodeRope, Rope.FromRefText[text]];
Log: Interpress.LogProc ~ { LogError[cmd.out, class, code, explanation] };
Progress: ProgressProc ~ {
IF begin THEN cmd.out.PutF["[%g", IO.int[page]]
ELSE cmd.out.PutRope["] "];
};
cmd.out.PutChar[' ];
InterpressToPD[inputName: inputName, outputName: outputName, params: specs.params, sx: specs.sx, sy: specs.sy, rotateDegrees: specs.rotateDegrees, tx: specs.tx, ty: specs.ty, skipPages: specs.skipPages, nPages: specs.nPages, logProc: Log, progressProc: Progress];
};
InterpressToPD: PUBLIC PROC [
inputName: ROPE, -- name of Interpress file
outputName: ROPE, -- name of PD file
params: PDParams, -- PD parameters
sx, sy: REAL ← 1.0, -- scale
tx, ty: REAL ← 0.0, -- translate
rotateDegrees: REAL ← 0.0, -- rotation (degrees)
skipPages: INT ← 0,
nPages: INTINT.LAST,
logProc: Interpress.LogProc ← NIL, -- called for errors during Interpress execution
progressProc: ProgressProc ← NIL -- called at the beginning and end of each page
] ~ {
interpress: Interpress.Master ~ Interpress.Open[inputName, logProc];
pd: ImagerPD.PD ← ImagerPD.CreateFromParameters[
name: outputName,
deviceCode: params.deviceCode,
sResolution: params.sRes,
fResolution: params.fRes,
imageSSize: Real.Round[params.pageSSize*params.sRes],
imageFSize: Real.Round[params.pageFSize*params.fRes],
toners: params.toners,
leftovers: params.leftovers,
bandSSize: params.bandSize,
maxLoadWords: params.load,
fontTuning: params.fontTuning,
tonerUniverse: params.tonerUniverse,
pixelsPerHalftoneDot: params.ppd,
ucr: params.ucr
];
FOR t: ImagerPD.Toner IN ImagerPD.Toner DO
IF params.bricks[t] # NIL THEN ImagerPD.SetHalftoneProperties[pd, t, params.bricks[t]];
ENDLOOP;
skipPages ← MIN[MAX[skipPages, 0], interpress.pages];
nPages ← MIN[nPages, interpress.pages-skipPages];
FOR i: INT IN [skipPages..skipPages+nPages) DO
page: INT ~ i+1;
action: PROC [context: Imager.Context] ~ {
IF tx#0.0 OR ty#0.0 THEN {
Imager.TranslateT[context, [tx*Imager.metersPerInch, ty*Imager.metersPerInch]];
};
IF rotateDegrees # 0.0 THEN {
Imager.RotateT[context, rotateDegrees];
};
IF sx#1.0 OR sy#1.0 THEN {
IF sx = sy THEN Imager.ScaleT[context, sx] ELSE Imager.Scale2T[context, [sx, sy]];
};
Interpress.DoPage[master: interpress, page: page, context: context, log: logProc];
};
IF progressProc#NIL THEN progressProc[begin: TRUE, page: page];
ImagerPD.DoPage[pd: pd, action: action, pixelUnits: FALSE];
IF progressProc#NIL THEN progressProc[begin: FALSE, page: page];
ENDLOOP;
ImagerPD.Close[pd];
};
PrinterType: TYPE ~ ImagerPD.PrinterType;
PrinterParams: TYPE ~ ARRAY PrinterType OF REF PDParams;
printerParams: REF PrinterParams ~ InitPrinterParams[];
InitPrinterParams: PROC RETURNS [pp: REF PrinterParams] ~ {
pp ← NEW[PrinterParams ← ALL[NIL]];
pp[bw400] ← NEW[PDParams ← [deviceCode: 12,
sRes: 400, fRes: 400, pageSSize: 13.75, pageFSize: 10.24,
toners: LIST[black],
leftovers: FALSE, bandSize: 50, load: 100000,
ppd: 7]];
pp[c150] ← NEW[PDParams ← [deviceCode: 10,
sRes: 120, fRes: 120, pageSSize: 11.0, pageFSize: 8.5,
toners: LIST[black, cyan, magenta, yellow],
leftovers: FALSE, bandSize: 48, load: 60000,
ppd: 4]];
pp[color400] ← NEW[PDParams ← [deviceCode: 9,
sRes: 400, fRes: 400, pageSSize: 13.75, pageFSize: 10.24,
toners: LIST[yellow, magenta, cyan, black],
leftovers: FALSE, bandSize: 50, load: 100000,
ppd: 7]];
pp[colorVersatec] ← NEW[PDParams ← [deviceCode: 7,
sRes: 200, fRes: 200, pageSSize: 163, pageFSize: 40,
toners: LIST[black, cyan, magenta, yellow],
leftovers: FALSE, bandSize: 64, load: 100000,
ppd: 5]];
pp[d4020] ← NEW[PDParams ← [deviceCode: 11,
sRes: 240, fRes: 120, pageSSize: 11.0, pageFSize: 8.5,
toners: LIST[black, cyan, magenta, yellow],
leftovers: FALSE, bandSize: 48, load: 60000,
ppd: 4]];
pp[plateMaker] ← NEW[PDParams ← [deviceCode: 4,
sRes: 1200, fRes: 1200, pageSSize: 12, pageFSize: 10,
toners: LIST[black],
leftovers: TRUE, bandSize: 16, load: 60000,
ppd: 11.312]];
pp[puffin] ← NEW[PDParams ← [deviceCode: 6,
sRes: 384, fRes: 384, pageSSize: 11.0, pageFSize: 8.5,
toners: LIST[cyan, magenta, yellow],
leftovers: TRUE, bandSize: 16, load: 60000,
ppd: 6]];
pp[raven300] ← NEW[PDParams ← [deviceCode: 1,
sRes: 300, fRes: 300, pageSSize: 8.5, pageFSize: 11.0,
toners: LIST[black],
leftovers: TRUE, bandSize: 16, load: 60000,
ppd: 5.656]];
pp[raven384] ← NEW[PDParams ← [deviceCode: 2,
sRes: 384, fRes: 384, pageSSize: 8.5, pageFSize: 11,
toners: LIST[black],
leftovers: TRUE, bandSize: 16, load: 60000,
ppd: 5.656]];
pp[versatec] ← NEW[PDParams ← [deviceCode: 7,
sRes: 200, fRes: 200, pageSSize: 163, pageFSize: 40,
toners: LIST[black],
leftovers: FALSE, bandSize: 64, load: 100000,
ppd: 5]];
};
ParamsFromPrinterType: PUBLIC PROC [type: ATOM] RETURNS [PDParams] ~ {
specs: Specs;
specs ← GetSpecs[Atom.GetPName[type], NIL];
RETURN [specs.params];
};
FontTranslator: PROC [c: Imager.Context, version: ROPE, cmd: Commander.Handle, verbose: BOOL] RETURNS [context: Imager.Context] ~ {
fontMap: ImagerFontFilter.FontMap ← xc1map;
RETURN [ImagerFontFilter.FilterFonts[c, fontMap, cmd, verbose]];
};
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 [char: CHAR, set: [0..256), code: [0..256)] RETURNS [ImagerFontFilter.CharRangeMap] ~ {
RETURN [[bc: CH[char], ec: CH[char], newbc: XC[set, code]]]
};
classicModernEtAl: LIST OF ROPELIST["Classic", "Modern"];
timesRomanEtAl: LIST OF LIST OF ROPELIST[LIST["TimesRoman", "Classic"], LIST["Helvetica", "Modern"], LIST["Gacha", "XeroxBook"], LIST["Tioga", "Classic"], LIST["Laurel", "Classic"]];
mrrEtAl: LIST OF ROPELIST["-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[];
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["Xerox/xc1-1-1/", 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["Xerox/xc1-1-1/", family.first.rest.first, face.first.Substr[4]], charMap: oisMap]],
warn: TRUE
]];
ENDLOOP;
ENDLOOP;
Enter[[
inputName: "Xerox/Pressfonts/Logo-mrr",
output: LIST[[newName: "Xerox/xc1-1-1/Logotypes-Xerox", charMap: alphaMap]]
]];
Enter[[
inputName: "Xerox/Pressfonts/Math-mrr",
output: LIST[[newName: "Xerox/xc1-1-1/Modern", charMap: mathMap]]
]];
Enter[[
inputName: "Xerox/Pressfonts/Math-mir",
output: LIST[[newName: "Xerox/xc1-1-1/Modern-italic", charMap: mathMap]]
]];
};
FindFullName: PROC [inputName: ROPE] RETURNS [ROPE] ~ {
fullFName: ROPENIL;
fullFName ← FS.FileInfo[inputName].fullFName;
RETURN [fullFName]
};
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];
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
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];
};
GetFileNameToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[FileNameTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
RealFromRope: PROC [rope: ROPE] RETURNS [real: REAL] = {
oops: BOOLFALSE;
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]];
};
Require: PROC [stream: IO.STREAM, rope: ROPE, case: BOOLEANFALSE] ~ {
IF NOT Rope.Equal[s1: rope, s2: GetCmdToken[stream], case: case] THEN Complain[Rope.Cat["Expected \"", rope, "\"."]];
};
Complain: PUBLIC ERROR [complaint: ROPE] ~ CODE;
MakeOutputName: PROC [inputName: ROPE, doc: ROPE] RETURNS [ROPE] ~ {
start: INT ← Rope.Index[s1: doc, s2: " to "]+4;
end: INT ← Rope.Index[s1: doc, pos1: start, s2: " "];
cp: FS.ComponentPositions;
isAIS: BOOL ← Rope.Equal[Rope.Substr[doc, start, end-start], "ais", FALSE];
[inputName, cp] ← FS.ExpandName[inputName];
RETURN [Rope.Cat[
Rope.Substr[inputName, cp.base.start, cp.base.length],
IF isAIS THEN NIL ELSE ".",
IF isAIS THEN NIL ELSE Rope.Substr[doc, start, end-start]
]]
};
Command: Commander.CommandProc ~ {
refAction: REF ActionProc ~ NARROW[cmd.procData.clientData];
stream: IO.STREAMIO.RIS[cmd.commandLine];
outputName: ROPE ← GetFileNameToken[stream];
secondTokenIndex: INTIO.GetIndex[stream];
gets: ROPE ← GetFileNameToken[stream];
inputName: ROPENIL;
IF NOT gets.Equal["←"] THEN {
inputName ← outputName;
outputName ← NIL;
stream.SetIndex[secondTokenIndex];
}
ELSE {inputName ← 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[" . . . "];
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
};
docIPToPD: ROPE ~ "Convert Interpress file to PD (output ← input printerType {{black | cyan | magenta | yellow} | (of (3 | 4)) | (<pixelsPerHalftoneDot> ppd) | (<tx> in <ty> in translate) | (<scale> (scale | scaleX | scaleY)) | (<skip> skipPages) | (<nPages> nPages) | leftovers | noLeftovers | (fontTuning <fontTuneSpec>) | (<pixelsPerInch> (sResolution | fResolution | Resolution)) | (<pageSizeInInches> (pageSSize | pageFSize)) | (<n> (bandSize | load | deviceCode)) | (<ucrParm> (gamma | threshold | removedFraction))})\n";
Commander.Register["PressToInterpress", Command, "Convert Press file to Interpress (output ← input [version])\n", NEW[ActionProc ← PressToInterpressAction]];
Commander.Register["AISToInterpress", Command, "Convert AIS file to Interpress (output ← input)\n", NEW[ActionProc ← AISToInterpressAction]];
Commander.Register["ColorAISToInterpress", Command, "Convert Color AIS file to Interpress (output ← input)\n", NEW[ActionProc ← AISToInterpressAction]];
Commander.Register["InterpressToPress", Command, "Convert Interpress file to Press (output ← input)\n", NEW[ActionProc ← InterpressToPressAction]];
Commander.Register["InterpressToJaM", Command, "Convert Interpress file to JaM (output ← input)\n", NEW[ActionProc ← InterpressToJaMAction]];
Commander.Register["InterpressToPD", Command, docIPToPD, NEW[ActionProc ← IPToPDAction]];
Commander.Register["IPToPD", Command, docIPToPD, NEW[ActionProc ← IPToPDAction]];
Commander.Register["ColorAISToInterpress", ColorAISToInterpressCommand, "Convert Color AIS files to Interpress (output ← inputRoot)\n"];
Commander.Register["InterpressToAIS", Command, "Convert Interpress file to AIS (outputRoot ← input) {Gray} {ppi: <pixels per inch>}\n", NEW[ActionProc ← InterpressToAISAction]];
END.