<<>> <> <> <> <> <<>> DIRECTORY BasicTime, Commander, FS, Imager, ImagerBackdoor, ImagerColor, ImagerDevice, ImagerPixelArray, ImagerPrivate, ImagerRaster, ImagerTransformation, InterpressInterpreter, IO, Prop, RasterEncodingStandardIO, RefTab, Rope, SF; InterpressImageExtractImpl: CEDAR PROGRAM IMPORTS Commander, BasicTime, FS, ImagerBackdoor, ImagerDevice, ImagerRaster, ImagerTransformation, InterpressInterpreter, IO, Prop, RasterEncodingStandardIO, RefTab, Rope ~ BEGIN Device: TYPE ~ ImagerDevice.Device; ROPE: TYPE ~ Rope.ROPE; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ msg: IO.STREAM, tab: RefTab.Ref, -- to avoid putting them out more than once nameRoot: ROPE, counter: CARD ¬ 0, sourceFileName: ROPE, page: INT ¬ 0 ]; RopeFromFactoredTransformation: PROC [f: ImagerTransformation.FactoredTransformation] RETURNS [ROPE] ~ { fRope: ROPE ¬ NIL; n: INT ¬ 0; IF f.t # [0, 0] THEN {n ¬ n + 1; fRope ¬ IO.PutFR["%g %g TRANSLATE", [real[f.t.x]], [real[f.t.y]]]}; IF f.r2 # 0 THEN {n ¬ n + 1; fRope ¬ IO.PutFR["%g ROTATE %g", [real[f.r2]], [rope[fRope]]]}; IF f.s # [1, 1] THEN { n ¬ n + 1; IF f.s.x = f.s.y THEN { fRope ¬ IO.PutFR["%g SCALE %g", [real[f.s.x]], [rope[fRope]]]; } ELSE { fRope ¬ IO.PutFR["%g %g SCALE2 %g", [real[f.s.x]], [real[f.s.y]], [rope[fRope]]]; }; }; IF f.r1 # 0 THEN {n ¬ n + 1; fRope ¬ IO.PutFR["%g ROTATE %g", [real[f.r1]], [rope[fRope]]]}; IF fRope = NIL THEN {n ¬ n + 1; fRope ¬ "1 SCALE"}; FOR i: INT IN [1..n) DO fRope ¬ Rope.Concat[fRope, " CONCAT"]; ENDLOOP; RETURN [fRope] }; GetScanOrder: PROC [pa: ImagerPixelArray.PixelArray] RETURNS [ImagerTransformation.Transformation] ~ { r: Imager.Rectangle ~ ImagerTransformation.TransformRectangle[pa.m, [0, 0, pa.sSize, pa.fSize]]; RETURN [ImagerTransformation.PostTranslate[pa.m, [-r.x, -r.y]]] }; DoPixelArray: PROC [device: Device, pa: ImagerPixelArray.PixelArray, m: ImagerTransformation.Transformation, mask: BOOL, colorOperator: ImagerColor.ColorOperator, remarks: ROPE] ~ { data: Data ~ NARROW[device.data]; res: RasterEncodingStandardIO.RES ~ NEW[RasterEncodingStandardIO.RESRep]; fileName: ROPE ¬ NARROW[RefTab.Fetch[x: data.tab, key: pa].val]; scanOrder: ImagerTransformation.Transformation ~ GetScanOrder[pa]; f: ImagerTransformation.FactoredTransformation ~ ImagerTransformation.Factor[m: ImagerTransformation.PostScale[ImagerTransformation.Cat[ImagerTransformation.Invert[scanOrder], pa.m, m], 0.001]]; fRope: ROPE ~ RopeFromFactoredTransformation[f]; normPA: ImagerPixelArray.PixelArray ¬ NEW[ImagerPixelArray.PixelArrayRep ¬ pa­]; normPA.m ¬ scanOrder; remarks ¬ Rope.Cat[fRope, " as ", remarks, " on page ", IO.PutFR1["%g", [integer[data.page]]]]; IF fileName # NIL THEN { IO.PutF[data.msg, "Repeat of %g: %g\n", [rope[fileName]], [rope[remarks]]]; RETURN }; IF mask THEN res.maskImage ¬ normPA ELSE res.colorImage ¬ normPA; IF colorOperator # NIL AND colorOperator.chromatic THEN { res.header ¬ "Interpress/Xerox/3.0/RasterEncoding/1.0 "; }; res.colorOperator ¬ colorOperator; fileName ¬ IO.PutFR["%g-%g.res", [rope[data.nameRoot]], [cardinal[data.counter]]]; data.counter ¬ data.counter + 1; res.imageProperties ¬ Prop.Put[propList: res.imageProperties, key: $name, val: Rope.Cat["Extracted from ", data.sourceFileName, ": ", remarks]]; res.imageProperties ¬ Prop.Put[propList: res.imageProperties, key: $creationTime, val: IO.PutFR1["%g", [time[BasicTime.Now[]]]]]; IF f.s.x/f.s.y IN [0.999..1.001] THEN { res.imageScale.x ¬ res.imageScale.y ¬ f.s.x; }; RasterEncodingStandardIO.Write[fileName: fileName, res: res]; fileName ¬ FS.FileInfo[name: fileName].fullFName; [] ¬ RefTab.Insert[x: data.tab, key: pa, val: fileName]; IO.PutF[data.msg, "%g: %g\n", [rope[fileName]], [rope[remarks]]]; }; ExtractSetColor: PROC [device: Device, color: ImagerColor.Color, viewToDevice: ImagerTransformation.Transformation] ~ { WITH color SELECT FROM color: ImagerColor.SampledColor => { DoPixelArray[device: device, pa: color.pa, m: color.um, mask: FALSE, colorOperator: color.colorOperator, remarks: "Sampled Color"] }; color: ImagerColor.SampledBlack => { DoPixelArray[device: device, pa: color.pa, m: color.um, mask: FALSE, colorOperator: NIL, remarks: IF color.clear THEN "Clear Sampled Black" ELSE "Sampled Black"] }; ENDCASE => NULL; device.state.allow ¬ [FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE] }; ExtractMaskBoxes: PROC [device: Device, bounds: SF.Box, boxes: SF.BoxGenerator] ~ { }; deviceClass: ImagerDevice.DeviceClass ~ NEW [ImagerDevice.DeviceClassRep ¬ [ SetColor: ExtractSetColor, MaskBoxes: ExtractMaskBoxes ]]; ExtractMaskPixel: PROC [context: Imager.Context, pa: ImagerPixelArray.PixelArray] ~ { DoPixelArray[device: ImagerRaster.GetDevice[context], pa: pa, m: ImagerBackdoor.GetT[context], mask: TRUE, colorOperator: NIL, remarks: "Mask"]; }; class: ImagerPrivate.Class ~ CreateClass[]; CreateClass: PROC RETURNS [ImagerPrivate.Class] ~ { class: ImagerPrivate.Class ~ ImagerRaster.CreateClass[type: $ExtractPixelArrays]; class.MaskPixel ¬ ExtractMaskPixel; RETURN [class] }; CreateContext: PROC [data: Data] RETURNS [Imager.Context] ~ { deviceParm: ImagerDevice.DeviceParm ~ ImagerDevice.MakeDeviceParm[ class: deviceClass, sSize: NAT.LAST, fSize: NAT.LAST, scanMode: [slow: right, fast: up], surfaceUnitsPerInch: [25.4, 25.4], surfaceUnitsPerPixel: 1 ]; context: Imager.Context ~ ImagerRaster.Create[class: class, deviceClass: deviceClass, deviceParm: deviceParm, data: data, pixelUnits: FALSE]; RETURN [context]; }; 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; }; OutputRoot: PROC [inputName: ROPE] RETURNS [ROPE] ~ { cp: FS.ComponentPositions; [inputName, cp] ¬ FS.ExpandName[inputName]; RETURN [Rope.Substr[inputName, cp.base.start, cp.base.length]]; }; Command: Commander.CommandProc = { <<[cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]>> ENABLE FS.Error => { result ¬ $Failure; msg ¬ error.explanation; IF error.group = user THEN CONTINUE; }; stream: IO.STREAM ~ IO.RIS[cmd.commandLine]; inputName: ROPE ¬ GetFileNameToken[stream]; Log: InterpressInterpreter.LogProc ~ { IO.PutRope[cmd.err, "IP Log: "]; IO.PutRope[cmd.err, explanation]; IO.PutRope[cmd.err, "\n"]; }; IF inputName = NIL THEN RETURN[result: $Failure, msg: cmd.procData.doc] ELSE { fullFName: ROPE ~ FS.FileInfo[inputName].fullFName; master: InterpressInterpreter.Master ~ InterpressInterpreter.Open[fullFName, Log]; data: Data ¬ NEW[DataRep ¬ [msg: cmd.out, tab: RefTab.Create[], nameRoot: OutputRoot[fullFName], sourceFileName: fullFName]]; context: Imager.Context ¬ CreateContext[data]; IO.PutF1[cmd.out, "Input file is %g . . .\n", [rope[fullFName]]]; FOR i: INT IN [1..master.pages] DO data.page ¬ i; InterpressInterpreter.DoPage[master: master, page: i, context: context, log: Log, copy: 1]; ENDLOOP; IO.PutF[cmd.out, "%g image%g extracted.\n", [cardinal[data.counter]], [rope[IF data.counter#1 THEN "s" ELSE ""]]]; InterpressInterpreter.Close[master: master]; }; }; Commander.Register[key: "IPImageExtract", proc: Command, doc: "Writes one RES (Raster Encoding Standard) file for each sampled image in the specified Interpress file"]; Commander.Register[key: "InterpressImageExtract", proc: Command, doc: "Writes one RES (Raster Encoding Standard) file for each sampled image in the specified Interpress file"] END.