CESConvertersCommand.mesa
Copyright Ó 1984, 1985, 1986, 1990, 1992 by Xerox Corporation. All rights reserved.
Michael Plass, November 2, 1990 1:00 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, April 8, 1988 4:29:45 pm PDT
Beretta:PARC:Xerox (8*923-4484) August 31, 1989 4:39:01 pm PDT
DIRECTORY
AIS,
Commander,
Convert,
ConvertRasterObject,
FileNames,
FS,
Imager,
ImagerColor,
ImagerColorES,
ImagerFont,
ImagerFontFilter,
ImagerInterpress,
ImagerPixelArray,
ImagerPixel,
ImagerSample,
ImagerBitmapContext,
ImagerRavenBitmapContext,
ImagerBackdoor,
ImagerSmoothContext,
SF,
CountedVM,
VM,
ImagerPress,
ImagerTransformation,
Interpress,
IO,
CESConverters,
Process,
Real,
Rope,
RopeFile,
RuntimeError,
ShowPress,
XeroxCompress;
CESConvertersCommand: CEDAR PROGRAM
IMPORTS AIS, Commander, Convert, FileNames, FS, Imager, ImagerRavenBitmapContext, ImagerColor, ImagerColorES, ImagerFont, ImagerFontFilter, ImagerInterpress, ImagerPixel, ImagerPixelArray, ImagerPress, ImagerSample, ImagerTransformation, ImagerSmoothContext, Interpress, IO, Process, Real, Rope, RopeFile, RuntimeError, ShowPress, VM, XeroxCompress, ImagerBackdoor, ConvertRasterObject
EXPORTS CESConverters
~ BEGIN OPEN CESConverters;
ROPE: TYPE ~ Rope.ROPE;
Types and constants
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;
};
BrickValue: TYPE ~ ARRAY [0..4) OF PACKED ARRAY [0..4) OF [0..16);
coarseBrickValues: BrickValue ¬ [ -- for compressed IP masters
[00, 01, 13, 14],
[08, 02, 03, 15],
[09, 10, 04, 05],
[07, 11, 12, 06]
];
MakeSimpleBrick: PROC [t: BrickValue] RETURNS [ImagerBitmapContext.Brick] ~ {
b: ImagerSample.SampleMap ¬ ImagerSample.NewSampleMap[box: [max: [4, 4]], bitsPerSample: 8];
FOR s: NAT IN [0..4) DO
FOR f: NAT IN [0..4) DO
ImagerSample.Put[b, [s, f], t[s][f]];
ENDLOOP;
ENDLOOP;
RETURN [[maxSample: 15, sampleMap: b, phase: 0]]
};
InterpressToCompressedIP: PUBLIC PROC [inputName: Rope.ROPE, interpress: ImagerInterpress.Ref, beginPage, endPage: ProgressProc, msg: IO.STREAM, pageWidth, pageHeight: REAL] RETURNS [failed: BOOL ¬ FALSE] ~ {
Generate a compressed master. IP master should be version 2.0 (otherwise why compress it ?). Errors are printed on msg if non-NIL, else raise errors. pageWidth and pageHeight (in meters) should be given as there is no way of recovering them from the source IP master (????).
Log: Interpress.LogProc ~ { IPReadLog[msg, class, code, explanation] };
input: Interpress.Master = Interpress.Open[FileNames.ResolveRelativePath[inputName], Log];
size: SF.Vec = [s: Real.Round[pageWidth*ravenPPM], f: Real.Round[pageHeight*ravenPPM]];
bitmap: ImagerSample.RasterSampleMap = ImagerSample.ObtainScratchMap[[max: size]];
bitmapAsPixelArray: ImagerPixelArray.PixelArray = ImagerPixelArray.FromPixelMap[pixelMap: ImagerPixel.MakePixelMap[bitmap], box: ImagerSample.GetBox[bitmap], scanMode: [slow: right, fast: up], immutable: FALSE];
bitmapContext: Imager.Context = ImagerRavenBitmapContext.Create[deviceSpaceSize: size, scanMode: [slow: right, fast: up], surfaceUnitsPerInch: [ravenPPI, ravenPPI], pixelUnits: FALSE, fontCacheName: $PrinterBitmap, deviceCode: $Raven300];
ImagerRavenBitmapContext.SetBitmap[context: bitmapContext, bitmap: bitmap];
ImagerRavenBitmapContext.SetBrick[context: bitmapContext, brick: MakeSimpleBrick[coarseBrickValues]];
WITH ImagerSample.GetRef[bitmap] SELECT FROM
vm: CountedVM.Handle => TRUSTED { VM.SwapIn[interval: vm.interval, kill: TRUE] };
ENDCASE => NULL;
FOR i: INT IN [1..input.pages] DO
PageAction: PROC [context: Imager.Context] ~ {
Imager.SetPriorityImportant[context, FALSE];
Imager.MaskPixel[context: context, pa: XeroxCompress.CompressPixelArray[bitmapAsPixelArray]]
};
Process.CheckForAbort[];
failed ¬ beginPage[i, input.pages];
IF failed THEN EXIT;
ImagerSample.Clear[bitmap];
Interpress.DoPage[master: input, page: i, context: bitmapContext, log: Log];
Process.CheckForAbort[];
ImagerInterpress.DoPage[interpress, PageAction, 0.0254/300.0];
Process.CheckForAbort[];
failed ¬ endPage[i, input.pages];
IF failed THEN EXIT;
ENDLOOP;
WITH ImagerSample.GetRef[bitmap] SELECT FROM
vm: CountedVM.Handle => TRUSTED { VM.Kill[interval: vm.interval] };
ENDCASE => NULL;
ImagerSample.ReleaseScratchMap[bitmap];
};
AISToInterpress: PUBLIC PROC [inputName: Rope.ROPE, interpress: ImagerInterpress.Ref, beginPage, endPage: ProgressProc, msg: IO.STREAM ¬ NIL, pageWidth, pageHeight: REAL, caption: ROPE] RETURNS [failed: BOOL ¬ FALSE] ~ {
Convert AIS file to IP master. Requires IP master to be at least version 3.1. pageWidth and pageHeight indicate page size in meters (IP conventions). The IP master is not closed on completion.
resolvedName: Rope.ROPE ¬ FileNames.ResolveRelativePath[inputName];
pa: Imager.PixelArray ¬ ImagerPixelArray.FromAIS[resolvedName];
maxSample: CARDINAL ~ ImagerPixelArray.MaxSampleValue[pa, 0];
rect: Imager.Rectangle ¬ ImagerTransformation.TransformRectangle[pa.m, [0, 0, pa.sSize, pa.fSize]];
scale: REAL ¬ MIN[(pageWidth-2*aisMargin)/rect.w, (pageHeight-2*aisMargin)/rect.h];
fRef: AIS.FRef ¬ AIS.OpenFile[resolvedName];
Paint: PROC [context: Imager.Context] ~ {
Caption: PROC ~ {
Imager.ScaleT[context, inch/72];
Imager.SetFont[context, ImagerFont.Scale[ImagerFont.Find[aisCaptionFont], 9]];
Imager.SetXY[context, aisCaptionLoc];
Imager.ShowRope[context, caption];
};
Imager.SetPriorityImportant[context, TRUE];
IF NOT caption.IsEmpty THEN 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)]];
Check for the 0 bit/pixel bitmaps here (Black on white)
IF fRef.raster.bitsPerPixel = 0 THEN
Imager.SetSampledColor[context: context, pa: pa, m: NIL, colorOperator: ImagerColor.NewColorOperatorGrayLinear[0, maxSample, maxSample+1]]
ELSE Imager.SetSampledColor[context: context, pa: pa, m: NIL, colorOperator: ImagerColor.NewColorOperatorGrayLinear[maxSample, 0, maxSample+1]];
Imager.MaskRectangle[context, rect];
};
IF beginPage[1, 1] THEN GOTO tooBad;
ImagerInterpress.DeclarePixelArray[interpress, pa];
ImagerInterpress.DoPage[self: interpress, action: Paint, scale: 1.0];
IF endPage[1, 1] THEN GOTO tooBad;
AIS.CloseFile[fRef];
EXITS
tooBad => failed ¬ TRUE;
};
ColorAISToInterpress: PUBLIC PROC [inputRed, inputGreen, inputBlue: Rope.ROPE, interpress: ImagerInterpress.Ref, beginPage, endPage: ProgressProc, msg: IO.STREAM, pageWidth, pageHeight: REAL, caption: ROPE] RETURNS [failed: BOOL ¬ FALSE] ~ {
Convert color AIS file to IP master. Requires IP master to be at least version 3.1. pageWidth and pageHeight indicate page size in meters (IP conventions). The IP master is not closed on completion.
pa: Imager.PixelArray;
maxSample: CARDINAL;
rect: Imager.Rectangle;
scale: REAL;
rgbArgs: ImagerColorES.RGBArgs ~ ImagerColorES.DefaultRGBArgs[];
Paint: PROC [context: Imager.Context] ~ {
Caption: PROC ~ {
Imager.ScaleT[context, inch/72];
Imager.SetFont[context, ImagerFont.Scale[ImagerFont.Find[aisCaptionFont], 9]];
Imager.SetXY[context, aisCaptionLoc];
Imager.ShowRope[context, caption];
};
Imager.SetPriorityImportant[context, TRUE];
IF NOT caption.IsEmpty THEN 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)]];
rgbArgs.swhite ¬ maxSample;
Imager.SetSampledColor[context: context, pa: pa, m: NIL, colorOperator: ImagerColorES.NewColorOperatorRGB[rgbArgs]];
Imager.MaskRectangle[context, rect];
};
pa ¬ ImagerPixelArray.Join3AIS[inputRed, inputGreen, inputBlue];
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];
IF beginPage[1, 1] THEN GOTO tooBad;
ImagerInterpress.DeclarePixelArray[interpress, pa];
ImagerInterpress.DoPage[self: interpress, action: Paint, scale: 1.0];
IF endPage[1, 1] THEN GOTO tooBad;
EXITS
tooBad => failed ¬ TRUE;
};
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
Interpress.classMasterError, Interpress.classAppearanceError => ERROR IPReadError[class, code, explanation];
Interpress.classMasterWarning, Interpress.classAppearanceWarning, Interpress.classComment => NULL; -- ignore those
ENDCASE => ERROR IPReadError[class, code, explanation];
}
ELSE {
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[" . . . "];
};
};
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: Interpress.LogProc ~ { IPReadLog[msg, class, code, explanation] };
input: Interpress.Master ¬ Interpress.Open[FileNames.ResolveRelativePath[inputName], Log];
FOR i: INT IN [1..input.pages] DO
Process.CheckForAbort[];
failed ¬ beginPage[i, input.pages];
IF failed THEN EXIT;
Interpress.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;
Interpress.Close[input];
};
InterpressToAIS: PUBLIC PROC [inputName: Rope.ROPE, outputBase: Rope.ROPE, msg: IO.STREAM, gray: BOOL, sPPI, fPPI: REAL, pageWidth, pageHeight: REAL] RETURNS [failed: BOOL ¬ FALSE] ~ {
Convert IP master to color/gray AIS file. sPPI and fPPI denote respectively the number of points per inch in the slow & fast scan directions. pageWidth and pageHeight are in meters. Only the 1st page of the master is converted. The suffix .ais is appended to outputBase to form the final file name if gray=TRUE, otherwise the suffixes -red.ais, -green.ais, -blue.ais are appended to outputBase to form the final file names.
MaxSample: ImagerPixel.PixelProc ~ {RETURN [255]};
Log: Interpress.LogProc ~ { IPReadLog[msg, class, code, explanation] };
sSize: REAL = pageHeight/inch;
fSize: REAL = pageWidth/inch;
box: SF.Box = [min: [0, 0], max: [s: Real.Round[sPPI*sSize], f: Real.Round[fPPI*fSize]]];
context: Imager.Context;
components: LIST OF ATOM = IF gray THEN LIST[$Intensity] ELSE LIST[$Red, $Green, $Blue];
pixelMap: ImagerPixel.PixelMap;
input: Interpress.Master;
pixelMap ¬ ImagerPixel.NewPixelMap[samplesPerPixel: (IF gray THEN 1 ELSE 3), box: box, maxSample: MaxSample];
context ¬ ImagerSmoothContext.Create[size: pixelMap.box.max, scanMode: Imager.defaultScanMode, initialScale: 1.0, cacheFonts: TRUE, surfaceUnitsPerPixel: 5];
ImagerSmoothContext.SetOutputBuffer[context, pixelMap, components];
Imager.SetColor[context, Imager.MakeGray[0]]; --set the master to white
Imager.MaskRectangle[context, ImagerBackdoor.GetBounds[context]];
Imager.SetColor[context, Imager.MakeGray[1]]; --set the master to white
Imager.Scale2T[context, [x: fPPI/inch, y: sPPI/inch]];
input ¬ Interpress.Open[FileNames.ResolveRelativePath[inputName], Log];
IF msg#NIL THEN msg.PutF["Imaging page 1 ..."];
Interpress.DoPage[master: input, page: 1, context: context, log: Log];
IF gray THEN {
name: ROPE ¬ Rope.Cat[outputBase, ".ais"];
ConvertRasterObject.AISFromSampleMap[name, pixelMap[0]];
IF msg#NIL THEN msg.PutF["%g ", IO.rope[name]];
}
ELSE {
red: ROPE ¬ Rope.Cat[outputBase, "-", "red", ".ais"];
green: ROPE ¬ Rope.Cat[outputBase, "-", "green", ".ais"];
blue: ROPE ¬ Rope.Cat[outputBase, "-", "blue", ".ais"];
ConvertRasterObject.AISFromSampleMap[red, pixelMap[0]];
ConvertRasterObject.AISFromSampleMap[green, pixelMap[1]];
ConvertRasterObject.AISFromSampleMap[blue, pixelMap[2]];
IF msg#NIL THEN msg.PutF["%g, %g, %g ", IO.rope[red], IO.rope[green], IO.rope[blue]];
};
Interpress.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.Cat[xcFontBase, "Logotypes-Xerox"], charMap: alphaMap]]
]];
Enter[[
inputName: "Xerox/Pressfonts/Math-mrr",
output: LIST[[newName: Rope.Cat[xcFontBase, "Modern"], charMap: mathMap]]
]];
Enter[[
inputName: "Xerox/Pressfonts/Math-mir",
output: LIST[[newName: Rope.Cat[xcFontBase, "Modern-italic"], charMap: mathMap]]
]];
};
Command level
PressToInterpressAction: PUBLIC ActionProc ~ {
BeginPage: ProgressProc ~ {cmd.out.PutF["[%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];
};
InterpressToCompressedIPAction: PUBLIC ActionProc ~ {
BeginPage: ProgressProc ~ {cmd.out.PutF["[%g", IO.int[pageNumber]]};
EndPage: ProgressProc ~ {cmd.out.PutRope["] "]};
output: ImagerInterpress.Ref ~ ImagerInterpress.Create[outputName, "Interpress/Xerox/2.0 "];
[] ¬ InterpressToCompressedIP[inputName, output, BeginPage, EndPage, cmd.out, defaultPageWidth, defaultPageHeight];
ImagerInterpress.Close[output];
};
AISToInterpressAction: PUBLIC ActionProc ~ {
BeginPage: ProgressProc ~ {
IF cmd.commandLine # NIL THEN cmd.out.PutF["[%g", IO.int[pageNumber]]};
EndPage: ProgressProc ~ {IF cmd.commandLine # NIL THEN cmd.out.PutRope["] "]};
output: ImagerInterpress.Ref ¬ ImagerInterpress.Create[outputName, headerSampled];
[] ¬ AISToInterpress[inputName, output, BeginPage, EndPage, cmd.out, defaultPageWidth, defaultPageHeight, cmd.commandLine];
ImagerInterpress.Close[output];
};
ColorAISToInterpressCommand: PUBLIC Commander.CommandProc ~ {
FileChoice: PROC [r: Rope.ROPE, a: ARRAY [0..3) OF Rope.ROPE]
RETURNS [result: Rope.ROPE ¬ NIL] ~ {
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;
};
BeginPage: ProgressProc ~ {IF NOT quiet THEN cmd.out.PutF["[%g", IO.int[pageNumber]]};
EndPage: ProgressProc ~ {IF NOT quiet THEN cmd.out.PutRope["] "]};
red, grn, blu: ROPE;
interpress: ImagerInterpress.Ref;
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 ¬ GetCmdToken[stream];
ok: BOOL ¬ FALSE;
inputName: ROPE ¬ NIL;
failed: BOOL;
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];
[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]];
interpress ¬ ImagerInterpress.Create[outputName, headerSampled];
IF quiet THEN cmd.commandLine ¬ NIL;
failed ¬ ColorAISToInterpress[red, grn, blu, interpress, BeginPage, EndPage, cmd.out, defaultPageWidth, defaultPageHeight, cmd.commandLine];
ImagerInterpress.Close[interpress];
IF failed THEN RETURN[result: $Failure, msg: "Interpress generation failed"];
outputName ¬ FindFullName[outputName];
cmd.out.PutRope["\n "];
cmd.out.PutRope[outputName];
cmd.out.PutRope[" written.\n"];
EXITS Quit => NULL
};
InterpressToPressAction: PUBLIC ActionProc ~ {
BeginPage: ProgressProc ~ {cmd.out.PutF["[%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];
};
InterpressToAISAction: PUBLIC ActionProc = {
sPixelsPerInch: REAL ¬ defaultAISPixelsPerInch;
fPixelsPerInch: REAL ¬ defaultAISPixelsPerInch;
sSize: REAL ¬ defaultPageHeight/inch; -- measured in inches
fSize: REAL ¬ defaultPageWidth/inch; -- measured in inches
gray: BOOL ¬ FALSE;
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 => Complain["\nIllegal value for ppi.\n"]];
Rope.Equal[token, "sppi:", FALSE] => sPixelsPerInch ¬ Convert.RealFromRope[r: GetCmdToken[cmds] ! Convert.Error => Complain["\nIllegal value for sppi.\n"]];
Rope.Equal[token, "fppi:", FALSE] => fPixelsPerInch ¬ Convert.RealFromRope[r: GetCmdToken[cmds] ! Convert.Error => Complain["\nIllegal value for fppi.\n"]];
Rope.Equal[token, "size:", FALSE] => {
fSize ¬ Convert.RealFromRope[r: GetCmdToken[cmds] ! Convert.Error => Complain["\nIllegal value for size.\n"]];
sSize ¬ Convert.RealFromRope[r: GetCmdToken[cmds] ! Convert.Error => Complain["\nIllegal value for size.\n"]];
};
ENDCASE => Complain[Rope.Cat["\nUnrecognized token: ", token, "\n"]];
ENDLOOP;
[] ¬ InterpressToAIS[inputName, outputName, cmd.out, gray, sPixelsPerInch, fPixelsPerInch, fSize*inch, sSize*inch];
};
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
};
Not used anywhere (but not removed in case...)
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: ROPE ¬ NIL] 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 ROPE ¬ LIST[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]]]];
};
Require: PROC [stream: IO.STREAM, rope: ROPE, case: BOOLEAN ¬ FALSE] ~ {
IF NOT Rope.Equal[s1: rope, s2: GetCmdToken[stream], case: case] THEN Complain[Rope.Cat["Expected \"", rope, "\"."]];
};
Currently disabled
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];
};
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", ColorAISToInterpressCommand, "Convert Color AIS file to Interpress (output ← input)\n", NIL];
Commander.Register["InterpressToPress", Command, "Convert Interpress file to Press (output ← input)\n", NEW[ActionProc ¬ InterpressToPressAction]];
Commander.Register["InterpressToCompressedIP", Command, "Convert Interpress file to IP master of compressed page bitmaps (output ← input)\n", NEW[ActionProc ← InterpressToCompressedIPAction]];
Commander.Register["InterpressToAIS", Command, "Convert Interpress file to AIS (outputRoot ← input) {Gray} {ppi: <pixels per inch>}\n", NEW[ActionProc ← InterpressToAISAction]];
END.