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: BOOLEAN ← FALSE;
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: BOOLEAN ← TRUE;
[] ← 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: BOOLEAN ← FALSE;
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: BOOLEAN ← FALSE;
tapeHandle: TapeHandle ← GetTapeHandle[];
input: IO.STREAM ← FS.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: ROPE ← NIL; char: CHAR ← IO.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: ROPE ← IO.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: BOOLEAN ← FALSE;
buffer: REF TEXT ← NIL;
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: NAT ← ORD[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: INTEGER ← SELECT 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.