PDInterpOutputTapeImpl.mesa
Last edited by Ken Pier, July 3, 1985 11:23:59 am PDT
DIRECTORY
Basics, PrincOpsUtils, MessageWindow, TapeOps, PDFileFormat, PDInterpSysCalls, PDInterpBitmap, PDInterpOutput, PDQueue, Rope
;
PDInterpOutputTapeImpl: CEDAR PROGRAM
IMPORTS PrincOpsUtils, MessageWindow, PDInterpBitmap, PDInterpSysCalls, TapeOps
EXPORTS PDInterpOutput = BEGIN
Plotter constants
bpi: CARDINAL = 200;
pageWidthInches: CARDINAL = 40;
white: CARDINAL = 0;
bitsPerWord: NAT = Basics.bitsPerWord;
bytesPerWord: NAT = Basics.bytesPerWord;
wordsPerScan: CARDINAL = ((bpi * pageWidthInches) + bitsPerWord - 1) / bitsPerWord;
scansPerBand: CARDINAL = 64;
wordsPerBand: LONG CARDINAL = LONG[wordsPerScan] * LONG[scansPerBand];
currentHerald: PDFileFormat.Herald;
currentStartImage: PDFileFormat.StartImage;
currentBandNumber: NAT ← 0;
bandWords: NAT ← 0;
band: PDInterpBitmap.BitmapDesc ← [sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: 0, fSize: 0, pointer: NIL, rast: 0, lines: 0];
bandWordsAllocated: INT ← 0;
tapeHandle: TapeOps.TapeHandle ← NIL;
preamble: REF ColorPreamble;
ColorPreamble: TYPE = MACHINE DEPENDENT RECORD [
 escape: [0..256) ← 9BH, -- escape
 header: CHARACTER,
 byteCountHigh: [0..256) ← 0,
 byteCountLow: [0..256) ← 4,
 lengthHigh: [0..256) ← 0,
 lengthLow: [0..256) ← 0,
 modeAndColor: ModeAndColor,
 reserved: [0..256) ← 0,
 padding: Bytepad --tape wants first record padded to 32 bytes
 ];
Bytepad: TYPE = ARRAY [0..12) OF CARDINAL;
pad: Bytepad = ALL[0];
Color: TYPE = MACHINE DEPENDENT {Black(0), Cyan(1), Magenta(2), Yellow(3)};
ColorMode: TYPE = MACHINE DEPENDENT {
SinglePassOfColor(0), FirstPassOfColor(1), IntermediatePassOfColor(2), (3)};
ModeAndColor: TYPE = MACHINE DEPENDENT RECORD [
padding: [0..16) ← 0, --4 bits of padding
mode: ColorMode, --2 bit field
color: Color ← Black ]; --2 bit field
CurrentBandDesc: PROC RETURNS [PDInterpBitmap.BitmapDesc] = TRUSTED {
band.sOrigin ← currentHerald.bandSSize*(currentBandNumber+currentStartImage.passBands);
PDInterpBitmap.Clear[band];
RETURN [band]
};
StartImage: PUBLIC PROC [herald: PDFileFormat.Herald, startImage: PDFileFormat.StartImage, request: PDQueue.Request] RETURNS [PDInterpBitmap.BitmapDesc] = {
IF taping THEN {
rast: NAT = (--startImage.fSizePage-- (bpi*pageWidthInches)+bitsPerWord-1)/bitsPerWord;
lines: INT = herald.bandSSize;
words: INT = rast*lines;
mode: ColorMode ← IF NOT startImage.feed THEN IntermediatePassOfColor ELSE IF startImage.strip THEN SinglePassOfColor ELSE FirstPassOfColor;
color: Color ← SELECT startImage.toner FROM
black => Black,
cyan => Cyan,
magenta => Magenta,
yellow => Yellow,
ENDCASE => ERROR;
currentHerald ← herald;
currentStartImage ← startImage;
currentBandNumber ← 0;
IF words > bandWordsAllocated THEN TRUSTED {
IF band.pointer # NIL THEN PDInterpSysCalls.FreeSpace[band.pointer];
band.pointer ← PDInterpSysCalls.AllocateSpace[words];
bandWordsAllocated ← words;
};
band.sOrigin ← 0;
band.fOrigin ← 0; -- startImage.fMinPage;
band.sMin ← 0;
band.fMin ← 0;
band.sSize ← herald.bandSSize;
band.fSize ← rast*bitsPerWord;
band.rast ← rast;
band.lines ← herald.bandSSize;
bandWords ← words;
IF bandWords MOD bufferWords # 0 THEN ERROR;
IF currentStartImage.feed THEN { --start of new page
tapeHandle ← InitializeTape[];
};
preamble ← MakeColorPreamble[inches: IF color=Black THEN LongestColor[]+2 ELSE 0, mode: mode, color: color];
TRUSTED {PutBlock[source: LOOPHOLE[preamble], words: SIZE[ColorPreamble]];};
IF passBands[color]#0 THEN SendWhiteSpace[bands: passBands[color]]
}
ELSE { --first pass to find images sizes and white space
rast: NAT = (--startImage.fSizePage-- (bpi*pageWidthInches)+bitsPerWord-1)/bitsPerWord;
lines: INT = herald.bandSSize;
words: INT = rast*lines;
color: Color ← SELECT startImage.toner FROM
black => Black,
cyan => Cyan,
magenta => Magenta,
yellow => Yellow,
ENDCASE => ERROR;
currentHerald ← herald;
currentStartImage ← startImage;
currentBandNumber ← 0;
IF words > bandWordsAllocated THEN TRUSTED {
IF band.pointer # NIL THEN PDInterpSysCalls.FreeSpace[band.pointer];
band.pointer ← PDInterpSysCalls.AllocateSpace[words];
bandWordsAllocated ← words;
};
band.sOrigin ← 0;
band.fOrigin ← 0; -- startImage.fMinPage;
band.sMin ← 0;
band.fMin ← 0;
band.sSize ← herald.bandSSize;
band.fSize ← rast*bitsPerWord;
band.rast ← rast;
band.lines ← herald.bandSSize;
bandWords ← words;
IF bandWords MOD bufferWords # 0 THEN ERROR;
buffersPerBand ← bandWords/bufferWords; --THIS MUST HAVE ZERO REMAINDER
IF currentStartImage.feed THEN { --start of new page, so initialize separation arrays
passBands ← ALL[LAST[NAT]];
nBands ← ALL[0];
};
passBands[color] ← currentStartImage.passBands;
nBands[color] ← currentStartImage.nBands;
};
RETURN [CurrentBandDesc[]];
};
MakeColorPreamble: PROC [inches: CARDINAL, mode: ColorMode, color: Color ← Black] RETURNS [preamble: REF ColorPreamble] = {
preamble ← NEW[ColorPreamble ← [
header: 'P,  -- color header preamble
lengthLow: inches, -- length in inches
modeAndColor: [mode: mode, color: color],
padding: pad
]];
};
PutBlock: PROC [source: LONG POINTER, words: NAT] = TRUSTED {
tapeStatus: TapeOps.TapeStatus;
loopCount: NAT ← words/bufferWords; --whole number of full buffers
lastBuffer: NAT ← words MOD bufferWords; --words in final, unfilled buffer
IF words > bandWordsAllocated THEN ERROR;
FOR count: NAT IN [0..loopCount) DO
MoveWordsToBuffer[from: source+LONG[bufferWords]*LONG[count], words: bufferWords];
tapeStatus ← TapeOps.WriteRecord[tapeHandle: tapeHandle, writeData: textBuffer];
ENDLOOP;
IF lastBuffer#0 THEN {
PrincOpsUtils.LongZero[where: bufferData, nwords: bufferWords];
MoveWordsToBuffer[from: source+LONG[bufferWords]*LONG[loopCount], words: lastBuffer];
tapeStatus ← TapeOps.WriteRecord[tapeHandle: tapeHandle, writeData: textBuffer];
};
};
MoveWordsToBuffer: PROC [from: LONG POINTER, words: NAT] = TRUSTED {
IF words > textBuffer.maxLength/2 THEN ERROR;
textBuffer.length ← words*2;
PrincOpsUtils.LongCopy[from: from, to: bufferData, nwords: words];
};
EndBand: PUBLIC PROC RETURNS [PDInterpBitmap.BitmapDesc] = TRUSTED {
IF taping THEN PutBlock[source: band.pointer, words: bandWords];
currentBandNumber ← currentBandNumber + 1;
RETURN [CurrentBandDesc[]]
};
EndImage: PUBLIC PROC [request: PDQueue.Request] = {
IF currentStartImage.strip THEN { -- all images completed for this page
minPass: NATLAST[NAT];
FOR c: Color IN Color DO
minPass ← MIN[passBands[c], minPass];
ENDLOOP;
FOR c: Color IN Color DO
IF passBands[c] # NAT.LAST THEN passBands[c] ← passBands[c] - minPass;
ENDLOOP;
IF taping THEN FinalizeTape[tapeHandle];
taping ← NOT taping;
}
ELSE IF taping THEN [] ← TapeOps.WriteFileMark[tapeHandle]; --file mark between separations
};
LongestColor: PROC [] RETURNS [inches: CARDINAL] = {
inches ← 0;
FOR c: Color IN Color DO
inches ← MAX[inches, ((passBands[c] + nBands[c]) * scansPerBand) / bpi];
ENDLOOP;
};
SendWhiteSpace: PROC [bands: CARDINAL] = TRUSTED {
PrincOpsUtils.LongZero[where: bufferData, nwords: bufferWords];
FOR i: CARDINAL IN [0..bands) DO
FOR j: CARDINAL IN [0..buffersPerBand) DO
PutBlock[source: bufferData, words: bufferWords];
ENDLOOP;
ENDLOOP;
};
InitializeTape: PROC RETURNS [tapeHandle: TapeOps.TapeHandle] = {
ENABLE TapeOps.TapeOpsError => {
IF tapeHandle#NIL THEN TapeOps.CloseDrive[tapeHandle]; ERROR};
tapeStatus: TapeOps.TapeStatus;
tapeHandle ← TapeOps.OpenDrive[serverName: serverName, driveNumber: driveNumber, density: density];
tapeStatus ← TapeOps.GetStatus[tapeHandle];
UNTIL tapeStatus[RDY] DO
MessageWindow.Append[message: "Tape Drive Not Ready", clearFirst: TRUE];
MessageWindow.Blink[];
tapeStatus ← TapeOps.GetStatus[tapeHandle];
ENDLOOP;
};
FinalizeTape: PROC [tapeHandle: TapeOps.TapeHandle] = {
ENABLE TapeOps.TapeOpsError => {TapeOps.CloseDrive[tapeHandle]; ERROR};
[] ← TapeOps.WriteFileMark[tapeHandle];
[] ← TapeOps.WriteFileMark[tapeHandle]; --need two file marks
[] ← TapeOps.Rewind[tapeHandle];
TapeOps.CloseDrive[tapeHandle];
};
SetTapeServer: PROC [serverNameL: Rope.ROPE ← "Maggie", driveNumberL: NAT ← 0, densityL: TapeOps.Density ← PE1600] = {
serverName ← serverNameL; driveNumber ← driveNumberL; density ← densityL;
};
serverName: Rope.ROPE ← "Maggie";
driveNumber: NAT ← 0;
density: TapeOps.Density ← PE1600;
taping: BOOLEANFALSE; --true if second pass and writing tapes
passBands: ARRAY Color OF NAT;
nBands: ARRAY Color OF NAT;
bufferData: LONG POINTER;
bufferBytes: NAT = 16000; --16 scanline buffer
bufferWords: NAT = bufferBytes/bytesPerWord;
bufferPad: NAT = 10; --just for debugging
textBuffer: REF TEXTNEW[TEXT[bufferBytes+bufferPad]];
buffersPerBand: NAT ← 0; --MUST BE AN INTEGRAL NUMBER OF BUFFERS PER BAND
textBuffer.length ← bufferBytes;
TRUSTED {bufferData ← LOOPHOLE[textBuffer, LONG POINTER]+SIZE[TEXT[0]];};
END.
look at ColorVersatecInterpOutputImpl which deals with XDE stuff band by band
look at PDInterpOutputViewerImpl to see how to get along in the Cedar world with ImagerPixelMaps. Combine the two, and then put in the tape file streams and control
commands. Think about naming and size of files.
Write a test tape BY HAND with four solid rectangles and send to Versatec.