OptronicsTapeImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Maureen Stone, October 8, 1989 1:04:26 pm PDT
Crow, April 4, 1989 7:01:48 pm PDT
Writes Optronics tape format.
The first record is a header block with a string in it
Each RGB image is three files, one per color, with one record per scanline
A gray image is a single file with one record per scanline
DIRECTORY
Rope USING [Equal, Fetch, FromChar, Length, ROPE, ToRefText, FromRefText, Cat, Substr],
CedarProcess USING [CheckAbort],
OptronicsTape,
Real USING [Round],
RealFns USING [Log, Power],
FS USING [ComponentPositions, Error, ExpandName, FileInfo, StreamOpen],
CommandTool USING [ArgumentVector, NumArgs, Parse],
Commander USING [CommandProc, Register],
Convert USING [CardFromRope, RopeFromTime],
BasicTime USING [Now],
AIS USING [CloseFile, CloseWindow, CreateFile, FRef, OpenWindow, Raster, RasterPart, WRef, WriteSample],
UnixTapeOps USING[BackSpaceFile, CloseDrive, CloseOpenConnections, Density, ForwardSpaceFile, OpenDrive, ReadRecord, Rewind, TapeHandle, WriteFileMark, WriteRecord ],
ImagerPixel USING [GetPixels, NewPixels, PixelBuffer, PixelMap, PixelMapRep],
ImagerSample USING [GetBox],
SF USING [SizeF, SizeS],
IO USING [EndOfStream, GetLineRope, PutRope, SP, STREAM],
UserCredentials USING [Get],
ConvertRasterObject USING [SampleMapFromAIS],
TapesCommon USING [FileHandleList, FileHandle, FileHandleRep];
OptronicsTapeImpl: CEDAR PROGRAM
IMPORTS BasicTime, CedarProcess, Commander, CommandTool, Convert, ConvertRasterObject, FS, ImagerPixel, ImagerSample, SF, UnixTapeOps, Rope, AIS, IO, -- Real, RealFns, -- UserCredentials
EXPORTS OptronicsTape
~ BEGIN OPEN OptronicsTape;
TapeError: PUBLIC SIGNAL [reason: ErrorDesc] = CODE;
ROPE: TYPE ~ Rope.ROPE;
TapeHandle: TYPE ~ UnixTapeOps.TapeHandle;
FileHandleList: TYPE ~ TapesCommon.FileHandleList;
FileHandle: TYPE ~ TapesCommon.FileHandle;
FileHandleRep: TYPE ~ TapesCommon.FileHandleRep;
PixelBuffer: TYPE ~ ImagerPixel.PixelBuffer;
PixelMap: TYPE ~ ImagerPixel.PixelMap;
sizeHeader: NAT ← 512;
red: NAT = 0;
green: NAT = 1;
blue: NAT = 2;
State: TYPE ~ REF StateRep;
StateRep: TYPE ~ RECORD [
interleaved: BOOLEAN,
tapeHandle: TapeHandle ← NIL,
buffer: REF TEXT ← NIL,
linesLeftInFile: INT,
rgbToDensity: TRCTable ← NIL
];
maxColorD: REAL ← 1.5;
maxGrayD: REAL ← 2.0;
headers: BOOLEANFALSE;
Write Tape
WriteTape: PUBLIC PROC [tapeHandle: TapeHandle, header: ROPE, files: FileSpecList] RETURNS [TapesCommon.FileHandleList] = {
Writes header and returns a list of FileHandle. Client rasterizes into each FileHandle in turn. newLine.eof is TRUE when tape has recorded nLines worth of rasters. Client can check newLine.eof to verify that the client and the tape are still in sync.
In separated format, a color file will generate 3 FileHandles: red, green and blue.
In interleaved format, a color file will generat 1 File handle that expects an RGB PixelBuffer
interleaved will proceed 3 times faster than separated format.
fileHandleList: FileHandleList ← NIL;
makeFileHandle: PROC [interleaved: BOOLEAN, rgbToDensity: TRCTable, pixels,lines: INT]
RETURNS[fileHandle: FileHandle] ~ {
state: State ← NEW[StateRep ← [
interleaved: interleaved,
tapeHandle: tapeHandle,
buffer: NEW[TEXT[pixels]],
linesLeftInFile: lines,
rgbToDensity: rgbToDensity
]];
fileHandle ← NEW[FileHandleRep ← [newLine: WriteNewLine, data: state]];
};
reverse: PROC[files: FileHandleList] RETURNS[r: FileHandleList] = {
r ← NIL;
FOR f: FileHandleList ← files, f.rest UNTIL f=NIL DO
r ← CONS[f.first, r];
ENDLOOP;
};
FOR f: FileSpecList ← files, f.rest UNTIL f=NIL DO
fileSpec: FileSpec ← f.first;
ppl: INT ← fileSpec.nPixels;
lines: INT ← fileSpec.nLines;
rgbToDensity: TRCTable ← MakeRGBToDensity[255,255, fileSpec.maxD];
fileHandleList ←
CONS[makeFileHandle[fileSpec.rgbInterleaved,rgbToDensity,ppl,lines],fileHandleList];
ENDLOOP;
IF headers THEN WriteTapeHeader[tapeHandle];
fileHandleList ← reverse[fileHandleList];
RETURN[fileHandleList];
};

GetTapeHandle: PROC [] RETURNS [TapeHandle] ~ {
tapeHandle: TapeHandle ← UnixTapeOps.OpenDrive["Chroma"];
RETURN[tapeHandle];
};
WriteTapeHeader: PROC [tapeHandle: TapeHandle] ~ {
Writes header and returns a descriptor
headerAsText: REF TEXT;
headerAsText ← Rope.ToRefText[ Rope.Cat[
"Written by ", UserCredentials.Get[].name,
" at ", Convert.RopeFromTime[BasicTime.Now[]]
]];
IF ~ headers THEN RETURN;
UnixTapeOps.Rewind[tapeHandle];
UnixTapeOps.WriteRecord[tapeHandle, headerAsText];
UnixTapeOps.WriteFileMark[tapeHandle];
};
PPIFromOptronics: PROC [pixelsPerInch: PixelsPerInch] RETURNS [ppi: NAT] ~ {
SELECT pixelsPerInch FROM
ppi63 => ppi ← 63;
ppi127 => ppi ← 127;
ppi254 => ppi ← 254;
ppi508 => ppi ← 508;
ppi1015 => ppi ← 1015;
ppi2030 => ppi ← 2030;
ENDCASE => SIGNAL TapeError[[$MisMatch, "illegitimate pixels per inch"]];
};
OptronicsFromPPI: PROC [ppi: NAT] RETURNS [pixelsPerInch: PixelsPerInch] ~ {
SELECT ppi FROM
63 => pixelsPerInch ← ppi63;
127 => pixelsPerInch ← ppi127;
254 => pixelsPerInch ← ppi254;
508 => pixelsPerInch ← ppi508;
1015 => pixelsPerInch ← ppi1015;
2030 => pixelsPerInch ← ppi2030;
ENDCASE => SIGNAL TapeError[[$MisMatch, "illegitimate pixels per inch"]];
};
WriteNewLine: PROC[self: FileHandle, line: PixelBuffer] RETURNS[eof: BOOLEAN] = {
state: State ← NARROW[self.data];
WriteScan: PROC[s: NAT] = {
FOR i: INT IN [0..line.length) DO
state.buffer[i] ← VAL[line[s][i]];
ENDLOOP;
state.buffer.length ← line.length;
UnixTapeOps.WriteRecord[state.tapeHandle, state.buffer];
};
RGBToDensity[line,state.rgbToDensity];
IF state.buffer=NIL OR state.buffer.maxLength < line.length
THEN state.buffer ← NEW[TEXT[line.length]];
IF state.interleaved THEN {
IF line.samplesPerPixel#3 THEN ERROR;
FOR i: NAT IN [0..3) DO WriteScan[i]; ENDLOOP;
}
ELSE WriteScan[0];
state.linesLeftInFile ← state.linesLeftInFile-1;
IF state.linesLeftInFile=0 THEN {
UnixTapeOps.WriteFileMark[state.tapeHandle];
eof ← TRUE;
};
};
CloseTape: PROC[self: TapeHandle] ~ {
UnixTapeOps.WriteFileMark[self];
UnixTapeOps.WriteFileMark[self];
UnixTapeOps.WriteFileMark[self];
UnixTapeOps.CloseDrive[self];  -- Close off tape
};
AISToTape: PROC [tapeHandle: TapeHandle, aisRoot: ROPE, color: BOOLEAN, pixelsPerInch: NAT, report: IO.STREAM ] ~ {
Writes single AIS file (3 for color) to tape.
PasteInLabel: PROC[fileRoot: Rope.ROPE, label: Rope.ROPE] RETURNS[Rope.ROPE] ~ {
cp: FS.ComponentPositions; fullFName, fName, ext: Rope.ROPE;
[fullFName, cp, ] ← FS.ExpandName[fileRoot];
IF cp.ext.length = 0
THEN {
fName ← Rope.Substr[ fullFName, 0, cp.ext.start];  -- name for filling in numbers
ext ← "ais";
}
ELSE {
fName ← Rope.Substr[ fullFName, 0, cp.ext.start-1];  -- drop "." before ext
ext ← Rope.Substr[ fullFName, cp.ext.start, cp.ext.length];
};
RETURN[ Rope.Cat[fName, label, ".", ext] ];
};
FindFile: PROC [fileRoot: Rope.ROPE, names: RECORD[ pref, alt, other: Rope.ROPE ] ]
RETURNS
[name: Rope.ROPE] ~ {
ok: BOOLEANTRUE;
[] ← FS.FileInfo[name ← PasteInLabel[fileRoot, names.pref]
     ! FS.Error => {ok ← FALSE; CONTINUE}];
IF ok THEN RETURN[ name ] ELSE ok ← TRUE;
[] ← FS.FileInfo[name ← PasteInLabel[fileRoot, names.alt]
     ! FS.Error => {ok ← FALSE; CONTINUE}];
IF ok THEN RETURN[ name ] ELSE ok ← TRUE;
[] ← FS.FileInfo[name ← PasteInLabel[fileRoot, names.other]
     ! FS.Error => {ok ← FALSE; CONTINUE}];
IF ok THEN RETURN[ name ] ELSE ok ← TRUE;
[] ← FS.FileInfo[name ← fileRoot ! FS.Error => {ok ← FALSE; CONTINUE}];
IF ok THEN RETURN[ name ]
ELSE {
SIGNAL TapeError[[
$MisMatch,
Rope.Cat[" Can't find ", fileRoot, " or with extensions: ",
   Rope.Cat[names.pref, " ", names.alt, " ", names.other] ]
]];
RETURN[ NIL ];
};
};
numFiles, xSize, ySize: NAT;
names: ARRAY[0..3) OF RECORD[ pref, alt, other: Rope.ROPE ];
pixels: PixelMap ← NEW[ImagerPixel.PixelMapRep[1]];
line: PixelBuffer;
ppi: PixelsPerInch ← OptronicsFromPPI[pixelsPerInch];
rgbToDensity: TRCTable;
IF color
THEN {
names[0] ← ["-red", "-r", NIL]; names[1] ← ["-grn", "-green", "-g"];
names[2] ← ["-blu", "-blue", "-b"];
numFiles ← 3;
rgbToDensity ← MakeRGBToDensity[255,255, maxColorD];
}
ELSE {
names[0] ← ["-gray", "-grey", NIL];
numFiles ← 1;
rgbToDensity ← MakeRGBToDensity[255,255, maxGrayD];
};
FOR i: NAT IN [0..numFiles) DO   -- get a file for each primary
fileName: Rope.ROPE ← FindFile[
aisRoot, names[i]
! TapeError => IF reason.code = $MisMatch THEN RESUME
];
IF fileName # NIL THEN {
eof: BOOLEANFALSE;
fileHandle: FileHandle;
pixels[0] ← ConvertRasterObject.SampleMapFromAIS[
aisfile: fileName, useVM: TRUE
];
pixels.box ← ImagerSample.GetBox[ pixels[0] ];
IF i = 0
THEN {
xSize ← SF.SizeF[pixels.box]; ySize ← SF.SizeS[pixels.box];
line ← ImagerPixel.NewPixels[1, xSize];
}
ELSE {
IF (xSize # SF.SizeF[pixels.box]) OR (ySize # SF.SizeS[pixels.box])
THEN ERROR TapeError[[$Fatal, "Separations not the same size"]];
};
fileHandle ← NEW[FileHandleRep ← [newLine: WriteNewLine, data: NEW[StateRep ← [
interleaved: FALSE,
tapeHandle: tapeHandle,
buffer: NEW[TEXT[xSize]],
linesLeftInFile: ySize,
rgbToDensity: rgbToDensity
]]]];
IF headers THEN {
UnixTapeOps.WriteRecord[ tapeHandle, Rope.ToRefText[ fileName ] ];
UnixTapeOps.WriteFileMark[tapeHandle];
};
IO.PutRope[report, Rope.Cat["Writing ", fileName, " "]];
FOR y: INTEGER IN [0..ySize) DO
CedarProcess.CheckAbort[];   -- respond to Stop button
ImagerPixel.GetPixels[self: pixels, initIndex: [s: y, f: 0], pixels: line, count: xSize];
eof ← WriteNewLine[self: fileHandle, line: line];
IF y = ((y / 100) * 100) THEN IO.PutRope[report, "."];
ENDLOOP;
IO.PutRope[report, " finished\n"];  -- filemark written by WriteNewLine
};
ENDLOOP;
};
OneAISToTape: PUBLIC PROC [aisRoot: ROPE, color: BOOLEAN, ppi: NAT, report: IO.STREAM] ~{
tapeHandle: TapeHandle ← GetTapeHandle[];
IF headers THEN WriteTapeHeader[tapeHandle];
AISToTape[tapeHandle, aisRoot, color, ppi, report];
CloseTape[tapeHandle];
};
CmdFileToTape: PUBLIC PROC [fileName: ROPE, report: IO.STREAM] ~ {
done: BOOLEANFALSE;
tapeHandle: TapeHandle ← GetTapeHandle[];
input: IO.STREAMFS.StreamOpen[fileName: fileName, accessOptions: $read];
IF headers THEN WriteTapeHeader[tapeHandle];
WHILE NOT done DO
GetWord: PUBLIC PROC[] RETURNS[ROPE] ~ {  -- Gets characters bound by white space
output: ROPENIL; char: CHARIO.SP;
WHILE char = IO.SP DO char ← Rope.Fetch[line, index]; index ← index + 1; ENDLOOP;
WHILE char # IO.SP DO           -- until trailing space
output ← Rope.Cat[ output, Rope.FromChar[char] ];
IF index >= Rope.Length[line] THEN EXIT;    -- exit if end
char ← Rope.Fetch[line, index];
index ← index + 1;
ENDLOOP;
RETURN[output];
};
line: ROPEIO.GetLineRope[ input ! IO.EndOfStream => EXIT ];
index, pixelsPerInch: NAT ← 0;
clr: ROPE ← GetWord[];
aisRoot: ROPE ← GetWord[];
color: BOOLEAN;
SELECT TRUE FROM
Rope.Equal[ "OptronicsfromGrayAIS", clr, FALSE] => color ← FALSE;
Rope.Equal[ "OptronicsfromGreyAIS", clr, FALSE] => color ← FALSE;
Rope.Equal[ "OptronicsfromColorAIS", clr, FALSE] => color ← TRUE;
ENDCASE => SIGNAL TapeError[[$MisMatch, "Bad color specification"]];
pixelsPerInch ← Convert.CardFromRope[GetWord[]];
AISToTape[tapeHandle, aisRoot, color, pixelsPerInch, report];
ENDLOOP;
CloseTape[tapeHandle];
};
Read Tape
ReadHeader: PUBLIC PROC [tapeHandle: TapeHandle] RETURNS [ROPE] = {
headerAsText: REF TEXT ← NIL;
fileMark: BOOLEAN;
UnixTapeOps.Rewind[tapeHandle];
[fileMark, headerAsText] ← UnixTapeOps.ReadRecord[tapeHandle];
IF fileMark THEN ERROR;
RETURN[Rope.FromRefText[headerAsText]];
};
aisColors: TYPE ~ {red, green, blue, gray};
AISInfo: TYPE ~ RECORD [fileName: ROPE, raster: AIS.Raster, fRef: AIS.FRef, wRef: AIS.WRef];
suffix: ARRAY aisColors OF ROPE = ["red", "grn", "blu",""];
FileToAIS: PUBLIC PROC [tapeHandle: TapeHandle, fileNumber: NAT, colorType: ColorType, aisRootName: ROPE, reduce: NAT ← 4] = {
Converts a tape file to 1 or 3 AIS files. Note that these are RGB density files.
If colorType=rgbSeparated the fileNumber should be the red file.
To see an individual separation use colorType=gray.
ais: ARRAY aisColors OF AISInfo;
nLines, nPixels: NAT ← 0;
fileMark: BOOLEANFALSE;
buffer: REF TEXTNIL;
SetUp: PROC [c: aisColors] = {
ais[c].raster ← NEW[AIS.RasterPart ← [scanCount: 1+nLines/reduce,
scanLength: 1+nPixels/reduce, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]];
ais[c].fileName ← Rope.Cat[r1: aisRootName, r2: "-", r3: suffix[c], r4: ".ais"];
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: aisColors] = {
AIS.CloseWindow[w: ais[c].wRef];
AIS.CloseFile[f: ais[c].fRef];
};
GetScan: PROC[c: aisColors, line: NAT] = {
scan: REF TEXT;
[fileMark, scan] ← UnixTapeOps.ReadRecord[tapeHandle, NIL];
IF fileMark THEN ERROR;
IF line MOD reduce #0 THEN RETURN;
FOR pixel: NAT IN [0 .. nPixels) DO
v: NATORD[scan[pixel]];
IF pixel MOD reduce #0 THEN LOOP;
AIS.WriteSample[w: ais[c].wRef, value: v, line: line/reduce, pixel: pixel/reduce];
ENDLOOP;
};
testFileMark: PROC = {
[fileMark, ] ← UnixTapeOps.ReadRecord[tapeHandle, NIL];
IF NOT fileMark THEN ERROR;
};
UnixTapeOps.Rewind[tapeHandle];
FOR i: NAT IN [0..fileNumber) DO--file 0 is the header
UnixTapeOps.ForwardSpaceFile[tapeHandle]; --skip over the unwanted files
ENDLOOP;
DO--determine the file size by reading the file
this is painful because reading all this data is noticeably slow.
We should probably develop more detailed header conventions
[fileMark, buffer] ← UnixTapeOps.ReadRecord[tapeHandle, buffer];
IF fileMark=TRUE THEN EXIT;
nLines ← nLines+1;
nPixels ← buffer.length;
ENDLOOP;
UnixTapeOps.BackSpaceFile[tapeHandle];
UnixTapeOps.BackSpaceFile[tapeHandle];
[fileMark, buffer] ← UnixTapeOps.ReadRecord[tapeHandle, buffer];
IF NOT fileMark THEN ERROR;
IF colorType=rgb THEN nLines ← nLines/3;
SELECT colorType FROM
rgb => {
FOR i: aisColors IN [red..blue] DO
SetUp[c: i];
ENDLOOP;
FOR lines: NAT IN [0 .. nLines) DO
FOR i: aisColors IN [red..blue] DO
GetScan[i, lines];
ENDLOOP;
ENDLOOP;
testFileMark[];
};
gray, singleColor => {
SetUp[c: gray];
FOR lines: NAT IN [0 .. nLines) DO
GetScan[gray, lines];
ENDLOOP;
testFileMark[];
Done[gray];
};
ENDCASE => ERROR;
IF colorType#gray THEN {
FOR i: aisColors IN [red..blue] DO Done[c: i]; ENDLOOP;
};
};
Utilities
Use a linear Density Ramp until I understand this better (July 24, 1989, M. Stone)
NewTRCTable: PROC [length: NAT] RETURNS [TRCTable] ~ {
trc: TRCTable ← NEW[TRCTableRec[length]];
trc.length ← length;
RETURN[trc];
};
MakeRGBToDensity: PUBLIC PROC[maxSampleOut, maxSampleIn: NAT ← 255, maxD: REAL ← 2.0] RETURNS[TRCTable] = {
Treats incoming RGB as linear intensity, outputs RGB in linear density for optronics transparencies.
This version makes a linear density map.
rgbToDensity: TRCTable ← NewTRCTable[maxSampleIn+1];
rgbToDensity[0] ← maxSampleOut;
FOR i: NAT IN [1..maxSampleIn] DO
rgbToDensity[i] ← maxSampleOut-i;
ENDLOOP;
RETURN[rgbToDensity];
};
MakeDensityToRGB: PUBLIC PROC[maxSampleOut, maxSampleIn: NAT ← 255, maxD: REAL ← 2.0] RETURNS[TRCTable] = {
Treats incoming RGB as linear intensity, outputs RGB in linear density for optronics transparencies.
This version makes a linear density map.
densityToRGB: TRCTable ← NewTRCTable[maxSampleIn+1];
densityToRGB[0] ← maxSampleOut;
FOR i: NAT IN [1..maxSampleIn] DO
densityToRGB[i] ← maxSampleOut-i;
ENDLOOP;
RETURN[densityToRGB];
};
MakeRGBToDensity: PUBLIC PROC[maxSampleOut, maxSampleIn: NAT ← 255, maxD: REAL ← 2.0] RETURNS[rgbToDensity, densityToRGB: TRCTable] = {
Treats incoming RGB as linear intensity, outputs RGB in linear density for optronics transparencies.
rgbToDensity: TRCTable ← NEW[TRCTableRec[maxSampleIn]];
densityToRGB: TRCTable ← NEW[TRCTableRec[maxSampleOut]];
density: PROC [pixel: NAT] RETURNS[REAL] = {
RETURN[RealFns.Log[base: 10, arg: REAL[maxSampleIn]/pixel]];
};
reflectance: PROC [pixel: NAT] RETURNS[REAL] = {
RETURN[1.0/RealFns.Power[base: 10, exponent: pixel/scale]];
};
scale: REAL ← maxSampleOut/maxD;
rgbToDensity ← NEW[TRCTableRec];
rgbToDensity[0] ← maxSampleOut;
densityToRGB ← NEW[TRCTableRec];
densityToRGB[0] ← maxSampleIn;
FOR i: NAT IN [1..maxSampleIn] DO
rgbToDensity[i] ← MIN[255, Real.Round[scale*density[i]]];
densityToRGB[i] ← MIN[255, Real.Round[reflectance[i]*maxSampleIn]];
ENDLOOP;
};
RGBToDensity: PUBLIC PROC [raster: PixelBuffer, rgbToDensity: TRCTable] = {
FOR j: NAT IN [0..raster.samplesPerPixel) DO
FOR i: NAT IN [0..raster.length) DO
raster[j][i] ← rgbToDensity[raster[j][i]];
ENDLOOP;
ENDLOOP;
};
DensityToRGB: PUBLIC PROC[raster: PixelBuffer, densityToRGB: TRCTable] = {
FOR j: NAT IN [0..raster.samplesPerPixel) DO
FOR i: NAT IN [0..raster.length) DO
raster[j][i] ← densityToRGB[raster[j][i]];
ENDLOOP;
ENDLOOP;
};
Sizes
sizeRecordGap: REAL ← 0.8; --the inter-record gap, in inches
sizeFileGap: REAL ← 2; --the inter-file gap, in feet
A big tape is 2400 feet, a small tape is 600 feet.
SizeOfFile: PUBLIC PROC [fileSpec: FileSpec, density: UnixTapeOps.Density ← GCR6250] RETURNS [sizeInFeet: REAL] = {
The file (three color files or one intensity file)
d: INTEGERSELECT density FROM GCR6250 => 6250, PE1600 => 1600, ENDCASE => ERROR;
scanLine: REAL ← sizeRecordGap+fileSpec.nPixels/d;
sep: REAL ← fileSpec.nLines*scanLine/12.0; --size in feet
IF fileSpec.rgbInterleaved THEN RETURN[3*sep+sizeFileGap] ELSE RETURN[sep+sizeFileGap];
};
SizeOfHeader: PUBLIC PROC [density: UnixTapeOps.Density ← GCR6250] RETURNS [sizeInFeet: REAL] = {RETURN[sizeFileGap+sizeHeader/12.0]};
SizeOfList: PUBLIC PROC [files: FileSpecList, density: UnixTapeOps.Density ← GCR6250] RETURNS [sizeInFeet: REAL] = {
Convenience proc. SizeOfFile for each file in list + SizeOfHeader
sizeInFeet ← SizeOfHeader[density];
FOR f: FileSpecList ← files, f.rest UNTIL f=NIL DO
sizeInFeet ← sizeInFeet+SizeOfFile[f.first, density];
ENDLOOP;
};
Commands
FileToTapeCmd: Commander.CommandProc ~ {
argv: CommandTool.ArgumentVector ~ CommandTool.Parse[cmd];
pxlsPerIn: NAT ← 254;
IF CommandTool.NumArgs[cmd] > 2 THEN pxlsPerIn ← Convert.CardFromRope[argv[2]];
WITH cmd.procData.clientData SELECT FROM
atom: ATOM => SELECT atom FROM
$Gray => OneAISToTape[aisRoot: argv[1], color: FALSE, ppi: pxlsPerIn, report: cmd.out ];
$Color => OneAISToTape[aisRoot: argv[1], color: TRUE, ppi: pxlsPerIn, report: cmd.out ];
$File => CmdFileToTape[fileName: argv[1], report: cmd.out ];
$CleanUp => UnixTapeOps.CloseOpenConnections[];
ENDCASE => ERROR;
ENDCASE => ERROR;
};
Commander.Register[
"OptronicsfromGrayAIS", FileToTapeCmd, "GrayAISToTape aisStem [pixelsPerInch]", $Gray
];
Commander.Register[
"OptronicsfromGreyAIS", FileToTapeCmd, "GreyAISToTape aisStem [pixelsPerInch]", $Gray
];
Commander.Register[
"OptronicsfromColorAIS", FileToTapeCmd, "ColorAISToTape aisStem [pixelsPerInch]", $Color
];
Commander.Register[
"OptronicsfromCmdFile", FileToTapeCmd, "CmdFileToTape cmdFile", $File
];
Commander.Register[
"OptronicsCleanUp", FileToTapeCmd, "CleanUp", $CleanUp
];
END.