<<>> <> <> <> <> <> <> <> <<>> 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 <> <> ROPE: TYPE ~ Rope.ROPE; Toner: TYPE ~ PrintColor.Toner; <> resHeader: ROPE ¬ "Interpress/Xerox/2.1/RasterEncoding/1.0 "; resSignature: INT = 13086; Complain: PUBLIC ERROR [complaint: ROPE] ~ CODE; <> 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; <> <> <> }; <> < TRUSTED { VM.SwapIn[interval: vm.interval, kill: TRUE] };>> < 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]; <> <> <> <> <> <> < { CONTINUE }]];>> <> <<};>> <<>> }; ENDLOOP; <> < TRUSTED { VM.Kill[interval: vm.interval] };>> < 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] }; <> <> <> <> <> <> <> <> <<};>> <<>> <> <<[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]]]; }; <> 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]; }; <> usage: ROPE ~ "Convert an Interpress file to an AIS format bitmap \nInterpressToBinaryAIS [ _] [-Resolution ] [-PixelsPerHalftoneDot ] [-Landscape] [-AllPages] [-Force] [-Trim] [-Width ] [-Height ] "; 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; <> <> <> <<>> << 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; <> halftoneProperties: PrintColor.HalftoneProperties ~ LIST[[type: $Black, toner: black, brick: ImagerBrick.BrickFromDotScreen[pixelsPerDot: brickPixelsPerDot, degrees: brickDegrees, shape: dotShape]]]; <> 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]; <> <> 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.