<> <> DIRECTORY Basics, PrincOpsUtils, MessageWindow, TapeOps, PDFileFormat, PDInterpSysCalls, PDInterpBitmap, PDInterpOutput, PDQueue, Rope ; PDInterpOutputTapeImpl: CEDAR PROGRAM IMPORTS PrincOpsUtils, MessageWindow, PDInterpBitmap, PDInterpSysCalls, TapeOps EXPORTS PDInterpOutput = BEGIN <> 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]; IF tapeStatus[EOT] THEN ERROR; ENDLOOP; IF lastBuffer#0 THEN { <> MoveWordsToBuffer[from: source+LONG[bufferWords]*LONG[loopCount], words: lastBuffer]; tapeStatus _ TapeOps.WriteRecord[tapeHandle: tapeHandle, writeData: textBuffer]; IF tapeStatus[EOT] THEN ERROR; }; }; 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: NAT _ LAST[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 { tapeStatus: TapeOps.TapeStatus; tapeStatus _ TapeOps.WriteFileMark[tapeHandle]; --file mark between separations IF tapeStatus[EOT] THEN ERROR; }; }; 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}; tapeStatus: TapeOps.TapeStatus; tapeStatus _ TapeOps.WriteFileMark[tapeHandle]; IF tapeStatus[EOT] THEN ERROR; tapeStatus _ TapeOps.WriteFileMark[tapeHandle]; --need two file marks IF tapeStatus[EOT] THEN ERROR; tapeStatus _ TapeOps.Rewind[tapeHandle]; IF tapeStatus[EOT] THEN ERROR; 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: BOOLEAN _ FALSE; --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 TEXT _ NEW[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. <> <> <<>> <> <<>>