<> <> <> <> <<>> <<>> <> <> <<>> <<>> DIRECTORY ConvertToRasters, CrosfieldTape, OptronicsTape, Interpress, Imager, Rope, InterpressToTape, ImagerPixel, ImagerSample, ImagerTransformation, ImagerMaskCapture, PrintColor, Real, AIS, FS, IO, MessageWindow, PrintColorTransformations, TapesCommon, UnixTapeOps, SF, ImagerBox; InterpressToTapeImpl: CEDAR PROGRAM IMPORTS ConvertToRasters, CrosfieldTape, Interpress, Real, AIS, Rope, Imager, FS, IO, MessageWindow, PrintColorTransformations, OptronicsTape, UnixTapeOps, ImagerTransformation, ImagerMaskCapture, ImagerBox EXPORTS InterpressToTape ~ BEGIN OPEN InterpressToTape; ROPE: TYPE ~ Rope.ROPE; ColorCorrection: TYPE ~ PrintColor.ColorCorrection; PixelBuffer: TYPE ~ ImagerPixel.PixelBuffer; ColorType: TYPE ~ OptronicsTape.ColorType; <> DefaultTapeSpec: PUBLIC PROC [name: ROPE, tapeNumber: NAT] RETURNS[TapeSpec] = { <> spec: TapeSpec _ NEW[TapeSpecRep _ [ note: name, tapeNumber: tapeNumber, serverName: "Chroma", drive: 0, density: GCR6250, tapeSize: 2400 ]]; RETURN[spec]; }; DefaultIPSize: PUBLIC PROC [name: ROPE, page: NAT _ 1, tol: REAL _ 0.02] RETURNS [fOrg, sOrg, fDim, sDim: REAL] = { <> m: Imager.Transformation _ ImagerTransformation.Scale[1/tol/0.0254]; -- ~1/tol pixels/inch n: Imager.Transformation _ ImagerTransformation.PostScale[m, 0.0254]; -- back to inches master: Interpress.Master _ Interpress.Open[name, NIL]; Operator: PROC [context: Imager.Context] ~ { Imager.SetColor[context, Imager.black]; Imager.SetStrokeEnd[context, square]; Imager.SetStrokeWidth[context, 0.0]; Imager.SetAmplifySpace[context, 1.0]; Interpress.DoPage[master, page, context, NIL]; }; b: SF.Box _ ImagerMaskCapture.CaptureBounds[Operator, m ! ImagerMaskCapture.Cant => RESUME]; r: ImagerBox.Rectangle _ ImagerTransformation.InverseTransformRectangle[ n, ImagerBox.RectangleFromBox[[b.min.s, b.min.f, b.max.s, b.max.f]]]; RETURN[fOrg: r.x, sOrg: r.y, fDim: r.w, sDim: r.h]; }; SizeFromIPSpecs: PUBLIC PROC[files: LIST OF IPSpec, format: Format, tapeSpec: TapeSpec] RETURNS[sizes: LIST OF Sizes, total: REAL] = { crosfield: FileAction = { fileSpec: CrosfieldTape.FileSpec _ NEW[CrosfieldTape.FileSpecRep _ [ pixelsPerInch: CrosfieldValToPPI[pixelsPerInch], nLines: nLines, nPixels: nPixels, note: name, mapPixel: CrosfieldTape.ByteToCrosfield ]]; size: REAL _ CrosfieldTape.SizeOfFile[fileSpec, tapeSpec.density]; sizes _ CONS[[name, size], sizes]; total _ total+size; }; optronics: FileAction = { fileSpec: OptronicsTape.FileSpec _ NEW[OptronicsTape.FileSpecRep _ [ pixelsPerInch: OptronicsValToPPI[pixelsPerInch], nLines: nLines, nPixels: nPixels, rgbInterleaved: NOT achromatic ]]; size: REAL _ OptronicsTape.SizeOfFile[fileSpec, tapeSpec.density]; sizes _ CONS[[name, size], sizes]; total _ total+size; }; SELECT format FROM optronics => { total _ OptronicsTape.SizeOfHeader[tapeSpec.density]; DoFileList[files: files, fileAction: optronics, reduceResolution: 1, format: format]; }; crosfield => { total _ CrosfieldTape.SizeOfHeader[tapeSpec.density]; DoFileList[files: files, fileAction: crosfield, reduceResolution: 1, format: format]; }; ENDCASE => ERROR; }; WillNotFit: PUBLIC SIGNAL = CODE; <> <<>> <> WriteTape: PUBLIC PROC [files: LIST OF IPSpec, format: Format, tapeSpec: TapeSpec] = { SELECT format FROM crosfield => WriteCrosfieldTape[files, tapeSpec]; optronics => WriteOptronicsTape[files, tapeSpec]; ENDCASE; }; <> <<>> <> <> <<>> Preview: PUBLIC PROC [files: LIST OF IPSpec, wd: ROPE _ NIL, reduceResolution: REAL _ 0.25] = { <> WriteRGBAIS[files: files, wd: wd, reduceResolution: reduceResolution, preview: TRUE]; }; WriteAIS: PUBLIC PROC [files: LIST OF IPSpec, format: Format, wd: ROPE _ NIL, reduceResolution: REAL _ 0.25] = { <> SELECT format FROM crosfield => WriteCrosfieldAIS[files: files, wd: wd, reduceResolution: reduceResolution]; optronics => WriteRGBAIS[files: files, wd: wd, reduceResolution: reduceResolution, preview: FALSE]; ENDCASE; }; <> InitCrosfieldTape: PUBLIC PROC [files: LIST OF IPSpec, tapeSpec: TapeSpec, rewindOnClose: BOOLEAN] = { <> tape: UnixTapeOps.TapeHandle _ UnixTapeOps.OpenDrive[tapeSpec.serverName, tapeSpec.drive, tapeSpec.density]; fileSpecList: CrosfieldTape.FileSpecList _ CrosfieldFromIPSpec[files]; size: REAL _ 0; <> size _ CrosfieldTape.SizeOfList[fileSpecList, tapeSpec.density]; IF size > tapeSpec.tapeSize THEN SIGNAL WillNotFit; CrosfieldTape.InitializeTape[tapeHandle: tape, files: fileSpecList, tapeNumber: tapeSpec.tapeNumber, name: tapeSpec.note]; IF rewindOnClose THEN UnixTapeOps.WriteEOT[tape]; UnixTapeOps.CloseDrive[tape, rewindOnClose]; }; AddToCrosfieldTape: PUBLIC PROC[tapeSpec: TapeSpec, fileNumber: NAT, file: IPSpec, inPosition, rewindOnClose: BOOLEAN] = { <> <> fileSpecList: CrosfieldTape.FileSpecList _ CrosfieldFromIPSpec[LIST[file]]; fileSpec: CrosfieldTape.FileSpec _ fileSpecList.first; --special case of a general procedure tape: UnixTapeOps.TapeHandle; tapeNotOpen: BOOLEAN _ TRUE; rasterize: FileAction ~ { crosfield: TapesCommon.FileHandle; rasterProc: ConvertToRasters.RasterProc = { --Callback from ConvertToRasters IF tapeNotOpen THEN { --wait to open the tape until rasters start coming tape _ UnixTapeOps.OpenDrive[serverName: tapeSpec.serverName, driveNumber: tapeSpec.drive,density: tapeSpec.density, rewind: FALSE]; crosfield _ CrosfieldTape.AddFileToTape[tape, fileSpec, fileNumber, tapeSpec.tapeNumber, inPosition]; tapeNotOpen _ FALSE; }; [] _ crosfield.newLine[crosfield, raster]; --send one raster to tape }; convert[rasterProc]; --images the InterpressMaster. May take a long time }; DoFileList[files: LIST[file], fileAction: rasterize, reduceResolution: 1, format: crosfield]; IF rewindOnClose THEN UnixTapeOps.WriteEOT[tape]; UnixTapeOps.CloseDrive[tape, rewindOnClose]; }; CrosfieldFromIPSpec: PROC[files: LIST OF IPSpec] RETURNS [fileSpecList: CrosfieldTape.FileSpecList] = { buildFileSpecs: FileAction ~ { fileSpec: CrosfieldTape.FileSpec _ NEW[CrosfieldTape.FileSpecRep _ [ pixelsPerInch: CrosfieldValToPPI[pixelsPerInch], nLines: nLines, nPixels: nPixels, note: name, mapPixel: CrosfieldTape.ByteToCrosfield ]]; fileSpecList _ CONS[fileSpec, fileSpecList]; }; reverseList: PROC[list: CrosfieldTape.FileSpecList] RETURNS [new: CrosfieldTape.FileSpecList] = { FOR l: CrosfieldTape.FileSpecList _ list, l.rest UNTIL l=NIL DO new _ CONS[l.first, new]; ENDLOOP; }; DoFileList[files: files, fileAction: buildFileSpecs, reduceResolution: 1, format: crosfield]; fileSpecList _ reverseList[fileSpecList]; --aesthetics }; WriteCrosfieldTape: PROC [files: LIST OF IPSpec, tapeSpec: TapeSpec] = { tape: UnixTapeOps.TapeHandle _ UnixTapeOps.OpenDrive[tapeSpec.serverName, tapeSpec.drive, tapeSpec.density]; fileSpecList: CrosfieldTape.FileSpecList _ CrosfieldFromIPSpec[files]; handleList, currentFile: TapesCommon.FileHandleList; size: REAL _ 0; rasterize: FileAction ~ { crosfield: TapesCommon.FileHandle _ currentFile.first; rasterProc: ConvertToRasters.RasterProc = { --Callback from ConvertToRasters [] _ crosfield.newLine[crosfield, raster]; --send one raster to tape }; currentFile _ currentFile.rest; convert[rasterProc]; --images the InterpressMaster }; <> size _ CrosfieldTape.SizeOfList[fileSpecList, tapeSpec.density]; IF size > tapeSpec.tapeSize THEN SIGNAL WillNotFit; handleList _ CrosfieldTape.WriteTape[tapeHandle: tape, files: fileSpecList, tapeNumber: tapeSpec.tapeNumber, name: tapeSpec.note]; currentFile _ handleList; --will be enumerated by rasterize DoFileList[files: files, fileAction: rasterize, reduceResolution: 1, format: crosfield]; UnixTapeOps.WriteEOT[tape]; UnixTapeOps.CloseDrive[tape]; }; WriteOptronicsTape: PROC [files: LIST OF IPSpec, tapeSpec: TapeSpec] = { tape: UnixTapeOps.TapeHandle _ UnixTapeOps.OpenDrive[tapeSpec.serverName, tapeSpec.drive, tapeSpec.density]; fileSpecList: OptronicsTape.FileSpecList; handleList, currentFile: TapesCommon.FileHandleList; size: REAL _ 0; buildFileSpecs: FileAction ~ { fileSpec: OptronicsTape.FileSpec _ NEW[OptronicsTape.FileSpecRep _ [ pixelsPerInch: OptronicsValToPPI[pixelsPerInch], nLines: nLines, nPixels: nPixels, rgbInterleaved: NOT achromatic, maxD: DefaultMaxD[achromatic] ]]; fileSpecList _ CONS[fileSpec, fileSpecList]; }; reverseList: PROC[list: OptronicsTape.FileSpecList] RETURNS [new: OptronicsTape.FileSpecList] = { FOR l: OptronicsTape.FileSpecList _ list, l.rest UNTIL l=NIL DO new _ CONS[l.first, new]; ENDLOOP; }; rasterize: FileAction ~ { fileHandle: TapesCommon.FileHandle _ currentFile.first; rasterProc: ConvertToRasters.RasterProc = { --Callback from ConvertToRasters [] _ fileHandle.newLine[fileHandle, raster]; --send one raster to tape }; currentFile _ currentFile.rest; convert[rasterProc]; --images the InterpressMaster }; <> DoFileList[files: files, fileAction: buildFileSpecs, reduceResolution: 1, format: optronics]; fileSpecList _ reverseList[fileSpecList]; --aesthetics <> size _ OptronicsTape.SizeOfList[fileSpecList, tapeSpec.density]; IF size > tapeSpec.tapeSize THEN SIGNAL WillNotFit; handleList _ OptronicsTape.WriteTape[tapeHandle: tape, header: tapeSpec.note, files: fileSpecList]; currentFile _ handleList; --will be enumerated by rasterize DoFileList[files: files, fileAction: rasterize, reduceResolution: 1, format: optronics]; UnixTapeOps.WriteEOT[tape]; UnixTapeOps.CloseDrive[tape]; }; AISInfo: TYPE ~ RECORD [fileName: ROPE, raster: AIS.Raster, fRef: AIS.FRef, wRef: AIS.WRef]; WriteRGBAIS: PROC [files: LIST OF IPSpec, wd: ROPE _ NIL, reduceResolution: REAL _ 0.25, preview: BOOLEAN] ~ { Color: TYPE ~ MACHINE DEPENDENT {red(0), green(1), blue(2), gray(3)}; colorSuffix: ARRAY Color OF ROPE = ["red", "grn", "blu", NIL]; fileAction: FileAction ~ { currentLine: NAT _ 0; ais: ARRAY Color OF AISInfo; rgbToDensity: OptronicsTape.TRCTable _ NIL; SetUp: PROC [c: Color] = { ais[c].raster _ NEW[AIS.RasterPart _ [scanCount: nLines, scanLength: nPixels, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]]; IF colorSuffix[c] = NIL THEN ais[c].fileName _ IO.PutFR["%g%g.ais", [rope[wd]], [rope[name]]] ELSE ais[c].fileName _ IO.PutFR["%g%g-%g.ais", [rope[wd]], [rope[name]], [rope[colorSuffix[c]]]]; ais[c].fRef _ AIS.CreateFile[name: ais[c].fileName, raster: ais[c].raster]; ais[c].wRef _ AIS.OpenWindow[f: ais[c].fRef]; }; Done: PROC [c: Color] = { AIS.CloseWindow[w: ais[c].wRef]; AIS.CloseFile[f: ais[c].fRef]; }; rasterProc: ConvertToRasters.RasterProc = { -- Callback from convert length: NAT ~ raster.length; writeLine: PROC[c: Color] = { wRef: AIS.WRef ~ ais[c].wRef; buf: ImagerSample.SampleBuffer ~ raster[ORD[c]]; -- the order better be right! <<*** for more speed, consider using AIS.UnsafeWriteLine here ***>> FOR pixel: NAT IN [0..length) DO AIS.WriteSample[w: wRef, value: buf[pixel], line: currentLine, pixel: pixel]; ENDLOOP; }; IF NOT preview THEN OptronicsTape.RGBToDensity[raster, rgbToDensity]; IF achromatic THEN writeLine[gray] ELSE FOR c: Color IN [red..blue] DO writeLine[c]; ENDLOOP; currentLine _ currentLine+1; }; IF achromatic THEN SetUp[gray] ELSE {SetUp[red]; SetUp[green]; SetUp[blue]}; IF NOT preview THEN rgbToDensity _ OptronicsTape.MakeDensityToRGB[255,255, DefaultMaxD[achromatic]]; convert[rasterProc]; -- call to image the Interpress Master IF achromatic THEN Done[gray] ELSE {Done[red]; Done[green]; Done[blue]}; }; DoFileList[files: files, fileAction: fileAction, reduceResolution: reduceResolution, format: optronics] }; <<>> <<>> WriteCrosfieldAIS: PROC [files: LIST OF IPSpec, wd: ROPE _ NIL, reduceResolution: REAL _ 0.25] ~ { Color: TYPE ~ MACHINE DEPENDENT {cyan(0), magenta(1), yellow(2), black(3)}; colorSuffix: ARRAY Color OF ROPE = ["cyan", "magenta", "yellow", "black"]; fileAction: FileAction ~ { currentLine: NAT _ 0; ais: ARRAY Color OF AISInfo; SetUp: PROC [c: Color] = { ais[c].raster _ NEW[AIS.RasterPart _ [scanCount: nLines, scanLength: nPixels, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]]; ais[c].fileName _ IO.PutFR["%g%g-%g.ais", [rope[wd]], [rope[name]], [rope[colorSuffix[c]]]]; ais[c].fRef _ AIS.CreateFile[name: ais[c].fileName, raster: ais[c].raster]; ais[c].wRef _ AIS.OpenWindow[f: ais[c].fRef]; }; Done: PROC [c: Color] = { AIS.CloseWindow[w: ais[c].wRef]; AIS.CloseFile[f: ais[c].fRef]; }; rasterProc: ConvertToRasters.RasterProc = { -- Callback from convert length: NAT ~ raster.length; FOR c: Color IN Color DO wRef: AIS.WRef ~ ais[c].wRef; buf: ImagerSample.SampleBuffer ~ raster[ORD[c]]; -- the order better be right! <<*** for more speed, consider using AIS.UnsafeWriteLine here ***>> FOR pixel: NAT IN [0..length) DO AIS.WriteSample[w: wRef, value: buf[pixel], line: currentLine, pixel: pixel]; ENDLOOP; ENDLOOP; currentLine _ currentLine+1; }; SetUp[cyan]; SetUp[magenta]; SetUp[yellow]; SetUp[black]; convert[rasterProc]; -- call to image the Interpress Master Done[cyan]; Done[magenta]; Done[yellow]; Done[black]; }; DoFileList[files: files, fileAction: fileAction, reduceResolution: reduceResolution, format: crosfield]; }; <<>> <<>> FileAction: TYPE ~ PROC [ name: ROPE, nLines, nPixels: NAT, pixelsPerInch: NAT, convert: PROC [ConvertToRasters.RasterProc], achromatic: BOOLEAN ] RETURNS [stop: BOOL _ FALSE]; metersPerInch: REAL = 0.0254; defaultCC: ColorCorrection _ PrintColorTransformations.SWOPWithGCLinearLStar[]; DoFileList: PROC [files: LIST OF IPSpec, fileAction: FileAction, reduceResolution: REAL _ 1, format: Format] ~ { log: Interpress.LogProc ~ {}; FOR list: LIST OF IPSpec _ files, list.rest UNTIL list=NIL DO ip: IPSpec _ list.first; IF ip=NIL THEN EXIT ELSE { name: ROPE ~ FileNameBase[ip.name]; comp: REAL _ Compensate[ip.pixelsPerInch, format]; --crosfield pixels aren't square nLines: NAT ~ Real.Round[0.5+ip.sDim*ip.pixelsPerInch*reduceResolution*comp]; nPixels: NAT ~ Real.Round[0.5+ip.fDim*ip.pixelsPerInch*reduceResolution]; rasterType: PROC RETURNS[ConvertToRasters.RasterType] = { IF format=crosfield THEN RETURN[cmyk] ELSE IF ip.achromatic THEN RETURN[gray] ELSE RETURN[rgb]; }; cc: PROC RETURNS[ColorCorrection] = { IF format=optronics THEN RETURN[NIL]; IF ip.colorCorrection=NIL THEN RETURN[defaultCC] ELSE RETURN[ip.colorCorrection]; }; rasterSpec: ConvertToRasters.RasterSpec _ [ type: rasterType[], fSize: nPixels, sSize: nLines, surfaceUnitsPerPixel: ip.surfaceUnitsPerPixel, colorCorrection: cc[] ]; convert: PROC [rasterProc: ConvertToRasters.RasterProc] ~ { <> [] _ ConvertToRasters.FromIP[ip: ip.name, ppiF: ip.pixelsPerInch*reduceResolution, ppiS: ip.pixelsPerInch*reduceResolution*comp, page: ip.page, rasterSpec: rasterSpec, proc: rasterProc, x: ip.fOrg, y: ip.sOrg, w: ip.fDim, h: ip.sDim]; }; MessageWindow.Append[IO.PutFR["Starting on %g, %g lines by %g pixels at %g", IO.rope[name], IO.int[nLines], IO.int[nPixels],IO.time[]], TRUE]; IF fileAction[name: name, nLines: nLines, nPixels: nPixels, pixelsPerInch: ip.pixelsPerInch, convert: convert, achromatic: ip.achromatic].stop THEN EXIT; } ENDLOOP; }; FileNameBase: PROC [name: ROPE] RETURNS [ROPE] ~ { fullFName: ROPE; cp: FS.ComponentPositions; [fullFName: fullFName, cp: cp] _ FS.ExpandName[name]; RETURN[Rope.Substr[fullFName, cp.base.start, cp.base.length]]; }; Compensate: PROC [ppi: REAL, format: Format] RETURNS [yScale: REAL] ~ { <> IF format=crosfield THEN yScale _ SELECT ppi FROM 300 => 304.8/300, 450 => 406.4/450, 600 => 609.6/600, ENDCASE => ERROR ELSE yScale _ 1; }; OptronicsValToPPI: PROC [val: NAT] RETURNS [ppi: OptronicsTape.PixelsPerInch] ~ { ppi _ SELECT val FROM 63 => ppi63, 127 => ppi127, 254 => ppi254, 508 => ppi508, 1015 => ppi1015, 2030 => ppi2030, ENDCASE => ERROR; }; CrosfieldValToPPI: PROC [val: NAT] RETURNS [ppi: CrosfieldTape.PixelsPerInch] ~ { ppi _ SELECT val FROM 300 => ppi300, 450 => ppi450, 600 => ppi600, ENDCASE => ERROR; }; DefaultMaxD: PROC [achromatic: BOOLEAN] RETURNS [REAL] ~ { RETURN[IF achromatic THEN 2.0 ELSE 1.4]; }; <> <<>> <<>> <> <> <<};>> <> <> <> <> <<};>> <> <> <> <<};>> END.