InterpressToBinaryAISImpl.mesa
Copyright Ó 1989, 1992 by Xerox Corporation. All rights reserved.
Michael Plass, November 7, 1989 5:04:45 pm PST
Kizer, November 7, 1989 5:33:31 pm PST
Maureen Stone, March 29, 1990 3:40:30 pm PST
Arnon, March 24, 1992 6:55 pm PST
Willie-s, April 2, 1992 8:09 pm PST
DIRECTORY
AISIO,
Commander USING [CommandProc, Handle, Register],
Convert,
FS,
Imager,
ImagerBitmapContext USING [Create, SetBitmap],
ImagerBackdoor,
ImagerBox USING [Rectangle],
ImagerError,
ImagerPixel,
ImagerPrintContext,
ImagerSample,
ImagerTransformation USING [ScanMode],
InterpressInterpreter USING [DoPage, LogProc, Master, Open],
IO,
PrintColor,
Real USING [Round],
Rope,
SF,
InterpressToBinaryAIS;
<<
-- old InterpressToBinaryAISImpl Directory
ImagerBrick,
FS,
SF,
ImagerPrintContext,
Imager,
ImagerSample,
AIS,
IO,
Rope,
Commander,
Interpress,
ImagerPrintColor,
PrintColor,
Real,
AISFormat,
CustomBrick,
RopeFile,
>>
InterpressToBinaryAISImpl: CEDAR PROGRAM
IMPORTS AISIO, Convert, Commander, FS, Imager, ImagerBitmapContext, ImagerBackdoor, ImagerError, ImagerPrintContext, ImagerSample, InterpressInterpreter, IO, Real, Rope, SF
<<
-- old InterpressToBinaryAISImpl IMPORTS
IMPORTS ImagerBrick, FS, SF, ImagerPrintContext, ImagerSample, AIS, IO, Rope, Commander, Interpress, Real, CustomBrick, RopeFile
>>
EXPORTS InterpressToBinaryAIS
~ BEGIN
Adapted (except old stuff) from /PCedar/RestrictedRES/RestrictedRESImpl.mesa.
Type Abbreviations for Imported Types
ROPE: TYPE ~ Rope.ROPE;
Toner: TYPE ~ PrintColor.Toner;
Constants
resHeader: ROPE ¬ "Interpress/Xerox/2.1/RasterEncoding/1.0 ";
resSignature: INT = 13086;
Complain: PUBLIC ERROR [complaint: ROPE] ~ CODE;
Conversion Procs
InterpressToBinaryAIS: PUBLIC PROC [inputName: Rope.ROPE, outputName: Rope.ROPE, resolution: INT ¬ 72, height: REAL ¬ 11.0, width: REAL ¬ 8.5, trim: BOOL ¬ TRUE, maskImage: BOOL ¬ TRUE, allPages: BOOL ¬ FALSE, pph: REAL ¬ 11.31371, compress: BOOL ¬ FALSE, landscape: BOOL ¬ FALSE, Log: InterpressInterpreter.LogProc ¬ NIL, resCheck: [1..16000) ¬ 72, force: BOOL ¬ FALSE] ~ {
res: INT ¬ resolution;
interpress: InterpressInterpreter.Master ~ InterpressInterpreter.Open[inputName, Log];
lowres: BOOL ~ res < 100.0;
pixelsPerHalftoneDot: REAL ¬ 11.31371;
deviceSpaceSize: SF.Vec ~ IF landscape THEN [s: Real.Round[width*res], f: Pad[Real.Round[height*res]]] ELSE [s: Real.Round[height*res], f: Pad[Real.Round[width*res]]]; -- res should be spots/inch, height, width should be inches
size: SF.Vec ~ [s: deviceSpaceSize.s, f: PadUp[deviceSpaceSize.f, trim]];
scanMode: ImagerTransformation.ScanMode ~ IF landscape THEN [slow: right, fast: up] ELSE [slow: down, fast: right];
bitmap: ImagerSample.RasterSampleMap ~ ImagerSample.ObtainScratchMap[[max: size]];
bitmapContext: Imager.Context ¬ NIL;
IF resCheck = 72 THEN {IF force THEN resCheck ¬ res ELSE resCheck ¬ CheckRes[res]}; -- redo this if default value supplied
IF pph=11.31371 THEN {IF res < 280 THEN pixelsPerHalftoneDot ¬ 11.31371*0.5 ELSE pixelsPerHalftoneDot ¬ 11.31371};
IF lowres
THEN {
bitmapContext ¬ ImagerBitmapContext.Create[deviceSpaceSize: deviceSpaceSize, scanMode: scanMode, surfaceUnitsPerInch: [res, res], pixelUnits: FALSE, fontCacheName: $Bitmap];
ImagerBitmapContext.SetBitmap[context: bitmapContext, bitmap: bitmap]
}
ELSE {
tonerUniverse: PrintColor.TonerUniverse
~ [black: TRUE, cyan: FALSE, magenta: FALSE, yellow: FALSE];
context: Imager.Context ¬ ImagerPrintContext.SimpleCreate[deviceSpaceSize: deviceSpaceSize, scanMode: scanMode, surfaceUnitsPerInch: [res, res], logicalDevice: 0, pixelsPerHalftoneDot: pixelsPerHalftoneDot, toners: tonerUniverse];
ImagerPrintContext.SetBitmap[context, bitmap];
ImagerPrintContext.SetSeparation[context, black];
Imager.SetWarn[context: context, warn: TRUE];
Imager.ClipRectangle[context, ImagerBackdoor.GetBounds[context]];
bitmapContext ¬ context;
bitmapContext ← ImagerRavenBitmapContext.Create[deviceSpaceSize: deviceSpaceSize, scanMode: scanMode, surfaceUnitsPerInch: [res, res], pixelUnits: FALSE, fontCacheName: $PrinterBitmap, deviceCode: IF res <= 400 THEN $Raven300 ELSE $BWPlatemaker];
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 page: INT IN [1..IF allPages THEN interpress.pages ELSE 1] DO
name: ROPE ~ IF allPages THEN Rope.Replace[base: outputName, start: Rope.Index[outputName, 0, "."], len: 0, with: IO.PutFR1["-%04g", [integer[page]]]] ELSE outputName;
ImagerSample.Clear[bitmap];
InterpressInterpreter.DoPage[master: interpress, page: page, context: bitmapContext, log: Log];
{
trimmed: SF.Box ~ Trim[bitmap, trim];
sampleMap: ImagerSample.SampleMap ¬ bitmap.Clip[trimmed];
dst: ImagerSample.SampleMap ¬ ImagerSample.NewSampleMap[box: trimmed, bitsPerSample: 1];
ImagerSample.Transfer[dst: dst, src: sampleMap, delta: SF.zeroVec, function: [null, complement]]; -- switch white/black sense
AISIO.Write[outputName, dst];
bitmapAsPixelArray: ImagerPixelArray.PixelArray ~ ImagerPixelArray.FromPixelMap[pixelMap: ImagerPixel.MakePixelMap[bitmap.Clip[trimmed]], box: trimmed, scanMode: scanMode, immutable: FALSE];
openFile: FS.OpenFile ~ FS.Create[name: name, setPages: TRUE, pages: 1000, fileType: [4428]];
ip: ImagerInterpress.Ref ~ ImagerInterpressBackdoor.CreateFragmentFromStream[FS.StreamFromOpenFile[openFile: openFile, accessRights: write], resHeader];
PushRESImage[inputName, ip, bitmapAsPixelArray, res, maskImage, compress];
ImagerInterpress.Close[ip];
IF allPages THEN {
cmd.out.PutRope[FindFullName[name ! FS.Error => { CONTINUE }]];
cmd.out.PutRope[" "];
};
};
ENDLOOP;
WITH ImagerSample.GetRef[bitmap] SELECT FROM
vm: CountedVM.Handle => TRUSTED { VM.Kill[interval: vm.interval] };
ENDCASE => NULL;
ImagerSample.ReleaseScratchMap[bitmap];
};
validResolutions: ROPE ¬ "72 75 150 200 254 300 400 508 600 1200";
CheckRes: PUBLIC PROC [res: INT] RETURNS [INT] ~ {
valid: IO.STREAM ¬ IO.RIS[Rope.Concat[validResolutions, " -1"]];
FOR i: INT ¬ IO.GetInt[stream: valid], IO.GetInt[stream: valid] UNTIL i < 0 DO
IF res = i THEN EXIT;
REPEAT FINISHED => Complain[Rope.Cat["RES bitmap resolution must be one of: ", validResolutions, "(or use -Force switch if you really mean it)"]]
ENDLOOP;
RETURN [res]
};
MakeSimpleBrick: PROC [t: ARRAY [0..4) OF PACKED ARRAY [0..4) OF [0..16)] 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]]
};
coarseBrickValues: ARRAY [0..4) OF PACKED ARRAY [0..4) OF [0..16) ← [
[00, 01, 13, 14],
[08, 02, 03, 15],
[09, 10, 04, 05],
[07, 11, 12, 06]
];
ActionProc: TYPE ~ PROC [inputName: ROPE, outputName: ROPE, cmd: Commander.Handle, switches: REF ARRAY CHAR['a..'z] OF REF ANY];
Pad: PROC [i: CARD] RETURNS [CARD] ~ { RETURN [((i+31)/32)*32] };
PadUp: PROC [i: CARD, trim: BOOL] RETURNS [CARD] ~ { RETURN [Pad[Pad[i]+(IF trim THEN 1 ELSE 0)]] };
Trim: PROC [bitmap: ImagerSample.SampleMap, trim: BOOL] RETURNS [trimmed: SF.Box] ~ {
trimmed ¬ (IF trim THEN ImagerSample.Trim[bitmap] ELSE ImagerSample.GetBox[bitmap]);
trimmed.max.f ¬ trimmed.min.f + Pad[SF.SizeF[trimmed]]; -- Some of the *&#!&*~ product printers pad pixelarrays incorrectly, so make sure they are a multiple of 32 in the fast direction.
};
GetCmdTokens: PROC [stream: IO.STREAM] RETURNS [LIST OF ROPE] ~ {
head: LIST OF ROPE ~ LIST[NIL];
last: LIST OF ROPE ¬ head;
FOR token: ROPE ¬ GetCmdToken[stream], GetCmdToken[stream] UNTIL token = NIL DO
last ¬ last.rest ¬ LIST[token];
ENDLOOP;
RETURN [head.rest]
};
GetIntSwitch: PROC [switches: REF ARRAY CHAR['a..'z] OF REF, name: CHAR['a..'z], default: INT] RETURNS [INT] ~ {
val: INT ~ IF switches[name] = NIL THEN default ELSE Convert.IntFromRope[NARROW[switches[name]]];
RETURN [val]
};
GetRealSwitch: PROC [switches: REF ARRAY CHAR['a..'z] OF REF, name: CHAR['a..'z], default: REAL] RETURNS [REAL] ~ {
val: REAL ~ IF switches[name] = NIL THEN default ELSE Convert.RealFromRope[NARROW[switches[name]]];
RETURN [val]
};
FindFullName: PROC [inputName: ROPE] RETURNS [ROPE] ~ {
fullFName: ROPE ¬ NIL;
fullFName ¬ FS.FileInfo[inputName].fullFName;
RETURN [fullFName]
};
FormatImagerError: PROC [error: ImagerError.ErrorDesc] RETURNS [ROPE] = {
RETURN [IO.PutFR["Imager.Error[[$%g, %g]]", [atom[ImagerError.AtomFromErrorCode[error.code]]], [rope[error.explanation]]]]
};
Command: Commander.CommandProc ~ {
refAction: REF ActionProc ~ NARROW[cmd.procData.clientData];
stream: IO.STREAM ¬ IO.RIS[cmd.commandLine];
outputName: Rope.ROPE ¬ NIL;
inputName: Rope.ROPE ¬ NIL;
switches: REF ARRAY CHAR['a..'z] OF REF ¬ NEW[ARRAY CHAR['a..'z] OF REF ¬ ALL[NIL]];
FOR token: Rope.ROPE ¬ GetCmdToken[stream], GetCmdToken[stream] UNTIL token = NIL DO
SELECT TRUE FROM
Rope.Equal[token, "←"] => {
IF outputName # NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc];
outputName ¬ inputName;
inputName ¬ NIL;
};
Rope.Fetch[token, 0] = '- => {
Match: PROC [pat: ROPE, unique: INT ¬ 2] RETURNS [BOOL] ~ {
matchLen: INT ~ Rope.Run[s1: pat, s2: token, case: FALSE];
RETURN [matchLen = Rope.Size[token] AND matchLen >= unique];
};
SELECT TRUE FROM
Match["-AllPages"] => switches['a] ¬ $TRUE;
Match["-Force"] => switches['f] ¬ $TRUE;
Match["-Trim"] => switches['t] ¬ $TRUE;
Match["-Resolution"] => switches['r] ¬ GetCmdToken[stream];
Match["-PixelsPerHalftoneDot"] => switches['p] ¬ GetCmdToken[stream];
Match["-pph"] => switches['p] ¬ GetCmdToken[stream];
Match["-MaskImage"] => switches['m] ¬ $TRUE;
Match["-Compress"] => switches['c] ¬ $TRUE;
Match["-Landscape"] => switches['l] ¬ $TRUE;
Match["-Width"] => switches['w] ¬ GetCmdToken[stream];
Match["-Height"] => switches['h] ¬ GetCmdToken[stream];
ENDCASE => RETURN[result: $Failure, msg: Rope.Cat["Unknown Switch: ", token, "\n", cmd.procData.doc]];
};
ENDCASE => {
IF inputName # NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc];
inputName ¬ token;
};
ENDLOOP;
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["Converting "];
cmd.out.PutRope[inputName];
cmd.out.PutRope[" . . . "];
refAction­[inputName, outputName, cmd, switches !
Convert.Error => {result ¬ $Failure; msg ¬ "Syntax error in command line: expected a number"; GOTO Quit};
Complain => {result ¬ $Failure; msg ¬ complaint; GOTO Quit};
FS.Error => {result ¬ $Failure; msg ¬ error.explanation; GOTO Quit};
Imager.Error => {result ¬ $Failure; msg ¬ FormatImagerError[error]; GOTO Quit}
];
IF switches['a]#$TRUE THEN {
outputName ¬ FindFullName[outputName !
FS.Error => { outputName ¬ "Output file(s)"; CONTINUE };
];
cmd.out.PutRope[outputName];
cmd.out.PutRope[" "];
};
cmd.out.PutRope["written.\n"];
EXITS Quit => NULL
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: Rope.ROPE] = {
rope ¬ NIL;
rope ¬ stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
CmdTokenBreak: 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];
};
ForceLower: Rope.TranslatorType ~ { RETURN [IF old IN ['A..'Z] THEN old-'A+'a ELSE old] };
MakeOutputName: PROC [inputName: Rope.ROPE, doc: Rope.ROPE] RETURNS [Rope.ROPE] ~ {
start: INT ¬ Rope.Index[s1: doc, s2: " to "]+4;
end: INT ¬ Rope.Index[s1: doc, pos1: start, s2: " "];
cp: FS.ComponentPositions;
[inputName, cp] ¬ FS.ExpandName[inputName];
RETURN [Rope.Cat[Rope.Substr[inputName, cp.base.start, cp.base.length], ".", Rope.Translate[doc, start, end-start, ForceLower]]];
};
Action Procs
InterpressToBinaryAISAction: ActionProc ~ {
Log: InterpressInterpreter.LogProc ~ {
cmd.out.PutF["Interpress error (class %g) %g: %g\n", IO.int[class], IO.atom[ImagerError.AtomFromErrorCode[code]], IO.rope[explanation]];
};
resolution: INT ~ CheckRes[GetIntSwitch[switches, 'r, 72]];
height: REAL ~ GetRealSwitch[switches, 'h, 11.0];
width: REAL ~ GetRealSwitch[switches, 'w, 8.5];
trim: BOOL ~ switches['t]=$TRUE;
maskImage: BOOL ~ switches['m]=$TRUE;
allPages: BOOL ~ switches['a]=$TRUE;
pph: REAL ~ GetRealSwitch[switches, 'p, IF resolution < 280 THEN 11.31371*0.5 ELSE 11.31371];
compress: BOOL ~ switches['c]=$TRUE;
landscape: BOOL ~ switches['l]=$TRUE;
resCheck: [1..16000) ~ IF switches['f]=$TRUE THEN resolution ELSE CheckRes[resolution];
InterpressToBinaryAIS[inputName: inputName, outputName: outputName, resolution: resolution, height: height, width: width, trim: trim, maskImage: maskImage, allPages: allPages, pph: pph, compress: compress, landscape: landscape, Log: Log, resCheck: resCheck];
};
Commands
usage: ROPE ~
"Convert an Interpress file to an AIS format bitmap \nInterpressToBinaryAIS [<outputName> ←] <inputName> [-Resolution <bitsPerInch(72)>] [-PixelsPerHalftoneDot <real>] [-Landscape] [-AllPages] [-Force] [-Trim] [-Width <inches(8.5)>] [-Height <inches(11.0)>]
";
action: REF ANY ¬ NEW[ActionProc ¬ InterpressToBinaryAISAction];
FOR l: LIST OF ROPE ¬ LIST["InterpressToBinaryAIS",
        "IPToBinaryAIS",
        "IPToBAIS"], l.rest WHILE l # NIL DO
Commander.Register[l.first, Command, usage, action];
ENDLOOP;
Old InterpressToBinaryAIS, InterpressToColorHalftoneAIS Commands
The code below was the content of a prior (unported) version of InterpressToBinaryAISImpl.mesa.
There are also an (old, unported) InterpressToAIS proc and command in CESConvertersCommand.mesa.
<<
QuotedStringError: ERROR = CODE;
CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '" THEN RETURN [break];
IF char = ' OR char = '\t OR char = ', OR char = '\l OR char = '\r THEN RETURN [sepr];
RETURN [other];
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [token: ROPE ¬ NIL] = {
token ¬ IO.GetTokenRope[stream, CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
IF Rope.Equal[token, "\""] THEN {
ref: REF;
IO.Backup[self: stream, char: '"];
ref ¬ IO.GetRefAny[stream ! IO.Error, IO.EndOfStream => ERROR QuotedStringError];
WITH ref SELECT FROM
rope: ROPE => token ¬ rope;
ENDCASE => ERROR QuotedStringError;
};
};
usageBW: ROPE ~ "usage: InterpressToBinaryAIS ipfile sPixelsPerInch fPixelsPerInch brickPixelsPerDot brickDegrees dotShape sSize fSize white";
docInterpressToBinaryAISCommand: ROPE ~
Rope.Concat["Convert an Interpress master to a one-bit-per-sample AIS file.\n", usageBW];
usageColor: ROPE ~ "usage: InterpressToColorHalftoneAIS ipfile sPixelsPerInch fPixelsPerInch dotFile sSize fSize white";
docInterpressToColorHalftoneAISCommand: ROPE ~
Rope.Concat["Convert an Interpress master to a one-bit-per-sample AIS file.\n", usageColor];
InterpressToBinaryAISCommand: Commander.CommandProc = {
[cmd: Commander.Handle] RETURNS [result: REF ANY ← NIL, msg: ROPE ← NIL]
ENABLE {
IO.Error => { msg ¬ usageBW; GOTO Fail };
QuotedStringError => { msg ¬ "QuotedStringError in command line"; GOTO Fail };
};
cmds: IO.STREAM ~ IO.RIS[cmd.commandLine];
fileName: ROPE ~ GetCmdToken[cmds];
interpress: Interpress.Master ~ Interpress.Open[fileName: fileName, log: NIL];
sRes: REAL ¬ IO.GetReal[stream: cmds];
fRes: REAL ¬ IO.GetReal[stream: cmds];
brickPixelsPerDot: REAL ¬ IO.GetReal[stream: cmds];
brickDegrees: REAL ¬ IO.GetReal[stream: cmds];
dotShape: REAL ¬ IO.GetReal[stream: cmds];
sSize: INT ¬ Real.Round[IO.GetReal[stream: cmds]*sRes];
fSize: INT ¬ ((Real.Round[IO.GetReal[stream: cmds]*fRes]+63)/64)*64;
white: NAT ¬ IO.GetInt[stream: cmds]; --0 or 1;
specs: ROPE ~ GetCmdToken[cmds];
halftoneProperties: PrintColor.HalftoneProperties ~ LIST[[type: $Black, toner: black, brick: ImagerBrick.BrickFromDotScreen[pixelsPerDot: brickPixelsPerDot, degrees: brickDegrees, shape: dotShape]]];
CustomBrick.HalftonePropertiesFromRope[specs: specs, tonerUniverse: [black: TRUE]];
context: Imager.Context ~ ImagerPrintContext.Create[
deviceSpaceSize: [sSize, fSize],
scanMode: [slow: down, fast: right],
surfaceUnitsPerInch: [fRes, sRes],
logicalDevice: 3333,
halftoneProperties: halftoneProperties,
correction: NIL,
interpolate: FALSE
];
bitmap: ImagerSample.SampleMap ¬ ImagerSample.ObtainScratchMap[box: [max: [sSize, fSize]], bitsPerSample: 1];
ImagerSample.Clear[bitmap];
ImagerPrintContext.SetBitmap[context: context, bitmap: bitmap];
ImagerPrintContext.SetSeparation[context: context, toner: black];
Interpress.DoPage[master: interpress, page: 1, context: context, log: NIL];
Interpress.Close[interpress];
msg ¬ WriteBinaryAIS[bitmap, MakeOutputName[fileName], Rope.Concat["InterpressToBinaryAIS", cmd.commandLine], (white=1)];
ImagerSample.ReleaseScratchMap[bitmap]; bitmap ¬ NIL;
EXITS Fail => { result ¬ $Failure };
};
InterpressToColorHalftoneAISCommand: Commander.CommandProc = {
[cmd: Commander.Handle] RETURNS [result: REF ANY ← NIL, msg: ROPE ← NIL]
ENABLE {
IO.Error => { msg ¬ usageColor; GOTO Fail };
QuotedStringError => { msg ¬ "QuotedStringError in command line"; GOTO Fail };
};
cmds: IO.STREAM ~ IO.RIS[cmd.commandLine];
fileName: ROPE ~ GetCmdToken[cmds];
interpress: Interpress.Master ~ Interpress.Open[fileName: fileName, log: NIL];
sRes: REAL ¬ IO.GetReal[stream: cmds];
fRes: REAL ¬ IO.GetReal[stream: cmds];
dotFile: ROPE ¬ GetCmdToken[cmds];
sSize: INT ¬ Real.Round[IO.GetReal[stream: cmds]*sRes];
fSize: INT ¬ ((Real.Round[IO.GetReal[stream: cmds]*fRes]+63)/64)*64;
white: NAT ¬ IO.GetInt[stream: cmds]; --0 or 1;
fourColorTU: PrintColor.TonerUniverse ~ [black: TRUE, cyan: TRUE, magenta: TRUE,
yellow: TRUE];
ext: ARRAY Toner OF ROPE ¬ ["-k", "-c", "-m", "-y",,,,,,,,,,,,];
halftoneProperties: PrintColor.HalftoneProperties ¬ CustomBrick.HalftonePropertiesFromRope[specs: RopeFile.SimpleCreate[name: dotFile], tonerUniverse: fourColorTU];
bitmap: ImagerSample.SampleMap ¬ ImagerSample.ObtainScratchMap[box: [max: [sSize, fSize]], bitsPerSample: 1];
context: Imager.Context;
cc: PrintColor.ColorCorrection ¬ DefaultCC;
FOR i: Toner IN [black..yellow] DO
context ¬ ImagerPrintContext.Create[
deviceSpaceSize: [sSize, fSize],
scanMode: [slow: down, fast: right],
surfaceUnitsPerInch: [fRes, sRes],
logicalDevice: 4444,
halftoneProperties: halftoneProperties,
correction: cc,
interpolate: FALSE
];
ImagerSample.Clear[bitmap];
ImagerPrintContext.SetBitmap[context: context, bitmap: bitmap];
ImagerPrintContext.SetSeparation[context: context, toner: i];
Interpress.DoPage[master: interpress, page: 1, context: context, log: NIL];
msg ¬ WriteBinaryAIS[bitmap, MakeOutputName[fileName, ext[i]], Rope.Cat["InterpressToColorHalftone", cmd.commandLine, "-*"], (white=1)];
ENDLOOP;
Interpress.Close[interpress];
ImagerSample.ReleaseScratchMap[bitmap];
bitmap ¬ NIL;
EXITS Fail => { result ¬ $Failure };
};
DefaultCC: PrintColor.ColorCorrection ¬ NEW[ PrintColor.ColorCorrectionRep ¬ [
type: $Default,
correctionProc: DefaultCCProc,
maxSampleIn: [255,255,255],
samplesPerPixelOut: 4,
data: NEW[CCDataRep ¬ [fraction: 0.4, threshold: 0.2]]
]];
CCData: TYPE = REF CCDataRep;
CCDataRep: TYPE = RECORD [fraction, threshold: REAL];
CorrectionProc: TYPE ~ PROC [self: ColorCorrection, pixelsOut: ImagerPixel.PixelBuffer, maxSampleOut: ARRAY [0..4) OF CARDINAL, rgbIn: ImagerPixel.PixelBuffer];
A sample value of 0 means no ink, and a sample value of maxSampleOut means full ink
DefaultCCProc: PrintColor.CorrectionProc ~ {
data: CCData ¬ NARROW[self.data];
FOR i: NAT IN [0..rgbIn.length) DO
c: REAL ¬ 1.0 - REAL[rgbIn[0][i]]/self.maxSampleIn[0];
m: REAL ¬ 1.0 - REAL[rgbIn[1][i]]/self.maxSampleIn[1];
y: REAL ¬ 1.0 - REAL[rgbIn[2][i]]/self.maxSampleIn[2];
min: REAL ¬ MIN[c,m,y];
ratio: REAL ¬ MAX[0, (min-data.threshold)/(1.0-data.threshold)];
k: REAL ¬ data.fraction*ratio*ratio;
pixelsOut[0][i] ¬ Real.Round[maxSampleOut[0]*c];
pixelsOut[1][i] ¬ Real.Round[maxSampleOut[1]*m];
pixelsOut[2][i] ¬ Real.Round[maxSampleOut[2]*y];
pixelsOut[3][i] ¬ Real.Round[maxSampleOut[3]*k];
ENDLOOP;
};
MakeOutputName: PROC [rope: ROPE, color: ROPE ¬ NIL] RETURNS [ROPE] ~ {
dot: INT ¬ Rope.FindBackward[s1: rope, s2: "."];
IF dot < 0 THEN dot ¬ Rope.FindBackward[s1: rope, s2: "!"];
IF dot < 0 THEN dot ¬ Rope.Size[rope];
RETURN [Rope.Replace[base: rope, start: dot, with: Rope.Cat[color,".ais"]]];
};
WriteBinaryAIS: PROC [sampleMap: ImagerSample.SampleMap, fileName: ROPE, comment: ROPE, largerIsLighter: BOOLEAN] RETURNS [newfilename: ROPE] ~ {
box: SF.Box ~ ImagerSample.GetBox[sampleMap];
size: SF.Vec ~ SF.Size[box];
raster: AIS.Raster ~ NEW[AIS.RasterPart ¬ [
scanCount: size.s,
scanLength: size.f,
scanMode: rd,
bitsPerPixel: 1, 
linesPerBlock: -1,
paddingPerBlock: 0
]];
photometry: AIS.Photometry ¬ NEW[AIS.PhotometryPart ¬ [
signal: blackAndWhite,
sense: IF largerIsLighter THEN largerIsLighter ELSE largerIsDarker,
scaleType: reflectance,
pointA: [0,0],
pointB: [1,1],
pointC: [0,-1],
spotType: rectangular,
spotWidth: 100,
spotLength: 100,
sampleMin: 0,
sampleMax: 1,
histogramLength: 0
]];
ais: AIS.FRef ~ AIS.CreateFile[name: fileName, raster: raster];
w: AIS.WRef ~ AIS.OpenWindow[ais];
line: ImagerSample.RasterSampleMap ~ ImagerSample.ObtainScratchMap[box: [max: [s: 1, f: size.f]], bitsPerSample: 1, bitsPerLine: size.f];
buffer: AIS.Buffer ~ [length: size.f/BITS[UNIT], addr: ImagerSample.GetBase[line].word];
AIS.WritePhotometry[ais, photometry, NIL];
AIS.WriteComment[ais, comment];
FOR s: INTEGER IN [0..size.s) DO
ImagerSample.BasicTransfer[dst: line, src: sampleMap, srcMin: [box.min.s+s, box.min.f], size: [1, size.f]];
TRUSTED {AIS.UnsafeWriteLine[w: w, buffer: buffer, line: s] };
ENDLOOP;
newfilename ¬ FS.GetName[ais.file].fullFName;
AIS.CloseFile[ais];
};
Commander.Register[key: "InterpressToBinaryAIS", proc: InterpressToBinaryAISCommand, doc: docInterpressToBinaryAISCommand];
Commander.Register[key: "InterpressToColorHalftoneAIS", proc: InterpressToColorHalftoneAISCommand, doc: docInterpressToColorHalftoneAISCommand];
>>
END.