-- CGBandImageImpl.mesa Cedar 3.4
-- Last changed by Ken Pier, October 8, 1982 4:06 pm

DIRECTORY
CGBandImage,
CGBandStream USING [BandPrefix, BandIndex, BandStreamHandle,
OpenBand, StartGetBand, GetBand, CloseBand ],
CGBandDevice USING [BandDevice, Band, BandRef, BandsRep, GetBParameters],
CGBandFormat USING [Bit, Marker, TBrickRef, tBrickSize,
   Run, runSize, Type,
   HeraldRef, HeraldObject, heraldObjectSize,
   ObjectRef, Object, objectSize],
CGArea USING [Ref],
GraphicsBasic USING [Box],
CGDevice USING [Ref, Rep],
CGMatrix USING [Ref, New],
CGSource USING [Rep, Ref],
CGStorage USING [qZone, pZone],
Inline USING [LongNumber, LowHalf, HighHalf, LongMult, DIVMOD],
UnsafeStorage USING [GetSystemUZone],
Real USING [FixC ],
Environment USING [bitsPerWord],
UserTerminal USING [CursorArray, SetCursorPattern, GetCursorPattern],
BitBlt USING [BBTableSpace, BBptr, AlignedBBTable, BITBLT],
CGBrickBLT USING [InitializeBrickBLT, BrickBLT],
--PressNetDefs USING [Printer, PageAttributes, PressSendError, PrinterReady,
-- SendPageAttributes, SendLine, CloseConnection, ScanDirection],
Space USING [Create, Delete, PageCount, wordsPerPage, CreateUniformSwapUnits,
Handle, nullHandle, virtualMemory, Map, LongPointer],
GraphicsOps USING [BitmapRef, NewBitmap, DrawBitmap],
TJaMGraphics USING [Painter],
Graphics USING [Context, SetCP, GetBounds, Box],
Runtime USING [CallDebugger];

CGBandImageImpl: PROGRAM
IMPORTS CGBandStream, CGBandDevice, CGMatrix, Real, --PressNetDefs,--
  Runtime, CGStorage, Space, Inline, CGBrickBLT, BitBlt, UnsafeStorage,
  GraphicsOps, TJaMGraphics, UserTerminal, Graphics
EXPORTS CGBandImage = {
OPEN GB: GraphicsBasic, BDevice: CGBandDevice, Device: CGDevice, Area: CGArea,
Matrix: CGMatrix, Source: CGSource, BStream: CGBandStream,
BFormat: CGBandFormat, BB: BitBlt, Real;

dataZone: ZONE = CGStorage.qZone;
repZone: ZONE = CGStorage.qZone;
pZone: ZONE = CGStorage.pZone;
uZone: UNCOUNTED ZONE ← UnsafeStorage.GetSystemUZone[];

NoPrinter: PUBLIC BOOLEANTRUE;
bitsPerWord: CARDINAL = Environment.bitsPerWord;

Error: SIGNAL = CODE;

myMark: BFormat.Marker;-- = 98765432

Data: TYPE = REF DataRep;
DataRep: TYPE = RECORD [
device: BDevice.BandDevice,
bitmap: GraphicsOps.BitmapRef ← NIL, --filled in if screen
base: LONG POINTERNIL, -- base address of band buffer or screen bitmap
pages: Space.PageCount 𡤀, -- pages in band buffer if not screen
rast: CARDINAL 𡤀, -- bitmap words per line
lines: CARDINAL 𡤀, -- bitmap lines
matrix: Matrix.Ref ← NIL,
bands: BDevice.BandRef ← NIL
];


New: PUBLIC PROC [bDevice: BDevice.BandDevice] RETURNS [Device.Ref] = {

data: Data ← dataZone.NEW[DataRep ← [device: bDevice, bitmap: NIL,
base: NIL, pages: 0,
rast: 0, lines: 0, matrix: NIL, bands: NIL]];
data.bands ← InitBands[bDevice];--verifies device type match
[base: , raster: data.rast, height: data.lines] ←
BDevice.GetBParameters[bDevice];--returns base=NIL
AcquireBandBitmap[data]; -- fill in bitmap, base, pages
data.matrix ← Matrix.New[];--Matrix.New returns a new identity matrix
RETURN[repZone.NEW[Device.Rep ← [
GetMatrix: GetMatrix, GetBounds: GetBounds, Show: Show,
GetRaster: GetRaster, data: data]]];
};

InitBands: PROC [bDevice: BDevice.BandDevice] RETURNS [bRef: BDevice.BandRef] = {

bandWidth, bandCount, bandHeight: CARDINAL ← 0;
wordsRead: LONG INTEGER ← 0;
bandName: STRING = "PBAND."L;
stream0: BStream.BandStreamHandle ← BStream.OpenBand[bandName, 0, read];
BStream.StartGetBand[stream0];
wordsRead ← BStream.GetBand[stream0, heraldRef, BFormat.heraldObjectSize];
IF wordsRead#BFormat.heraldObjectSize OR heraldRef.mark#myMark THEN Runtime.CallDebugger["HeraldErr"L];
IF heraldRef.device#bDevice THEN Runtime.CallDebugger["HeraldDevMismatch"L];
bandWidth ← heraldRef.bandWidth; bandCount ← heraldRef.bandCount;
bandHeight ← heraldRef.bandHeight;

bRef ← repZone.NEW[BDevice.BandsRep[bandCount] ←
   [count: bandCount, height: bandHeight,
   width: bandWidth, list: ]];
bRef[0] ← [ymin: 0.0, ymax: bandHeight,
stream: stream0];
FOR i: CARDINAL IN [1..bandCount) DO
bRef[i] ← [ymin: i*bandHeight, ymax: (i+1)*bandHeight,
stream: BStream.OpenBand[ bandName, i, read]];
ENDLOOP;
runsRef ← uZone.NEW[RunsBuffer[bandHeight]];
lineRef ← uZone.NEW[Scanline[maxLx2+(bandWidth*bitsPerWord)]];--brickline limit is (L+xmax+L-1) bits
};--InitBands

AcquireBandBitmap: PROC[data: Data] = { -- updates data directly

SELECT data.device FROM
IN [hornet..end] => { -- get a space for band buffer
longrast, longtemp, longDiv: LONG CARDINAL;--KLUDGE
longDiv ← data.bands.count*Space.wordsPerPage;
longrast ← data.rast;
longtemp ← ((longrast*data.lines)+longDiv-1)/longDiv;
-- number of words per image (+normalize for arithmetic)/(256 words per diskpage * # bands per image)
IF Inline.HighHalf[longtemp]#0 THEN ERROR;
data.pages ← Inline.LowHalf[longtemp];
newSpace ← Space.Create[size: data.pages, parent: Space.virtualMemory];
Space.CreateUniformSwapUnits[size: 63, parent: newSpace];
Space.Map[newSpace];--use default window
data.base ← Space.LongPointer[newSpace];
};
screen => { -- get a bitmap from CedarGraphics
data.bitmap ←
GraphicsOps.NewBitmap[width: data.rast*bitsPerWord, height: data.lines];
data.base ← LOOPHOLE[data.bitmap.base];
};
ENDCASE => ERROR;
};--AcquireBandBitmap

SpaceZero: PROC[base: LONG POINTER, pages: Space.PageCount ← 0] = {

a: LONG POINTER TO ARRAY [0..Space.wordsPerPage) OF WORDLOOPHOLE[base];
FOR i: CARDINAL IN [0..pages) DO
a^ ← ALL[0];
a ← a+Space.wordsPerPage;
ENDLOOP;
};--SpaceZero

GetMatrix: SAFE PROC[self: Device.Ref] RETURNS[Matrix.Ref] = CHECKED {
data: Data ← NARROW[self.data];
RETURN[data.matrix];
};

GetBounds: SAFE PROC[self: Device.Ref] RETURNS[GB.Box] = TRUSTED {
data: Data ← NARROW[self.data];
w: CARDINAL ← 16*data.rast;
h: CARDINAL ← data.lines;
e: REAL = 0.1; -- small fudge factor
RETURN[[xmin: e, ymin: e, xmax: w-e, ymax: h-e]];
};

GetRaster: SAFE PROC [self: Device.Ref] RETURNS[LONG POINTER,CARDINAL] = TRUSTED {
data: Data ← NARROW[self.data];
RETURN[data.base,data.rast];
};

Show: SAFE PROC[self: Device.Ref, area: Area.Ref, src: Source.Ref,
map: CGMatrix.Ref] = TRUSTED {
-- data: Data ← NARROW[self.data];
-- UNTIL Area.Empty[area] DO
-- trap: Trap ← Area.Remove[area];
-- ShowTrap[data,trap,trapType,src,myBand];
-- ENDLOOP;
Runtime.CallDebugger["Can't Show"L];
};

Close: PUBLIC PROC[self: Device.Ref] = {
data: Data ← NARROW[self.data];
bands: BDevice.BandRef ← data.bands;
bcount: CARDINAL ← bands.count;

FOR bI: BStream.BandIndex IN [0..bcount) DO
BStream.CloseBand[bands[bI].stream]; ENDLOOP;
KillSpace[];
};--Close

KillSpace: PUBLIC PROC[] = {
IF newSpace#Space.nullHandle THEN {Space.Delete[newSpace]; newSpace←Space.nullHandle;};
};--KillSpace

-- Modd copied from CGBrickImpl
Modd: PROC[x, y: LONG INTEGER] RETURNS [LONG INTEGER] = INLINE {
RETURN [IF x >= 0 THEN (x MOD y) ELSE ((y-1) + (x+1) MOD y)];
};--Modd

GetNextOb: PROC [band: BDevice.Band, index: BStream.BandIndex, objRef: BFormat.ObjectRef] = {
--GetNextOb takes a band and a buffer and puts an object head for this band
--into the buffer, then fills in globals RunsBuffer, tBrick buffer, as appropriate.

OPEN BFormat;
runWords, brickWords: CARDINAL ← 0;
wordsRead: LONG INTEGER;

wordsRead ← BStream.GetBand[band: band.stream, to: objRef, words: objectSize];
IF wordsRead#objectSize THEN Runtime.CallDebugger["GetObReadErr"L];
IF objRef.mark#myMark THEN Runtime.CallDebugger["GetObMarkErr"L];
IF objRef.flags.type=end THEN RETURN;
IF objRef.band#index THEN ERROR;

runWords ← IF objRef.flags.rect THEN BFormat.runSize ELSE BFormat.runSize*objRef.height;
wordsRead ← BStream.GetBand[band: band.stream, to: runsRef, words: runWords];--read runs
SELECT objRef.flags.type FROM
all0, all1, bits => RETURN; --no data for allx, scanlines later for bits
brick => { --tBrick and runs. Read brick.
wordsRead ← BStream.GetBand[band: band.stream, to: tBrick, words: tBrickSize];
IF wordsRead # tBrickSize THEN
Runtime.CallDebugger["InitBrickReadErr"L];--ran off end of stream ?!
brickWords ← (tBrick.brickSize + bitsPerWord-1)/bitsPerWord;
wordsRead ← BStream.GetBand[band: band.stream, to: brickBuffer, words: brickWords];
IF wordsRead # brickWords THEN
Runtime.CallDebugger["InitBrickReadErr"L];--ran off end of stream ?!
IF maxL<tBrick.L THEN Runtime.CallDebugger["InitBrickMaxLErr"L];
RETURN };--tBrick
fontcache, herald, end => ERROR;
ENDCASE => ERROR;
};--GetNextOb

ShowBands: PUBLIC PROC [bDevice: BDevice.BandDevice] = {

data: Data;
bands: BDevice.BandRef;
bandCount, bandWidth, bandHeight: CARDINAL;
goAhead: BOOLEANFALSE;
dev: Device.Ref ← New[bDevice];--opens up band files
data ← NARROW[dev.data];--data should contain the band device parameters !!
bands ← data.bands;
bandCount ← bands.count;
bandWidth ← bands.width;
bandHeight ← bands.height;
yOffset ← 0;--assumes screen bitmap

-- BEGIN OPEN PressNetDefs;
-- ENABLE PressSendError => { Runtime.CallDebugger["PressNetErr"L]; GOTO exit; };
-- pageAttributes: PageAttributes;
-- printer: Printer;
-- scanDirection: ScanDirection;
--
-- SELECT bDevice FROM
-- IN [hornet..end) => {
-- SELECT bDevice FROM
-- hornet => {printer ← Stinger; scanDirection ← landscape};
-- platemaker => {printer ← DLP1; scanDirection ← portrait};
-- ENDCASE => ERROR;
-- IF ~NoPrinter THEN {
-- IF ~(goAhead ← PrinterReady[printer, 2])
-- THEN { Runtime.CallDebugger["PrinterNoGo"L]; GOTO exit;};
-- pageAttributes ← [scanDirection: scanDirection, filler: , firstScan: 0D, lastScan: data.lines-1, margin: 0, bitWc: data.rast];
-- SendPageAttributes[@pageAttributes];
-- };
-- };
-- screen => NULL;
-- ENDCASE => ERROR;
-- EXITS
-- exit => { Close[dev];
-- IF goAhead THEN {PressNetDefs.CloseConnection[]; goAhead ← FALSE};
-- RETURN;
-- };----exit
-- END;

FOR bI: BStream.BandIndex IN [0..bandCount) DO
myBand: BDevice.Band ← bands[bI];
IF bI#0 THEN BStream.StartGetBand[myBand.stream]; -- init the stream buffer for the new band
SELECT bDevice FROM
IN [hornet..end) => {
yOffset ← Real.FixC[myBand.ymin];-- band relative baseline
SpaceZero[data.base, data.pages];
};
screen => NULL;
ENDCASE => ERROR;
CursorCode[bI];

--GetNextOb takes a band and a buffer and puts an object head for this band
--into the buffer, then fills in globals RunsBuffer, tBrick buffer, Scanline
-- as appropriate.

DO
GetNextOb[band: myBand, index: bI, objRef: objectRef];
SELECT objectRef.flags.type FROM
all0, all1, bits, brick => Render[data: data, stream: myBand.stream];
herald => ERROR;
end => EXIT;
ENDCASE=> ERROR;

ENDLOOP;--for each trap UNTIL end of band

-- IF ~NoPrinter AND goAhead THEN {----sending to printer
-- OPEN PressNetDefs;
-- ENABLE PressSendError => { Runtime.CallDebugger["PressNetErr"L]; GOTO exit; };
-- tp: LONG POINTER ← data.base;
-- SetFTPBoxes[];
-- FOR i: CARDINAL IN [0..bandHeight) DO
-- PressNetDefs.SendLine[tp];
-- tp ← tp + data.rast;
-- [] ← InvertCursor[];
-- ENDLOOP;
-- EXITS
-- exit => { Close[dev];----clean up open bands
-- IF goAhead THEN {PressNetDefs.CloseConnection[]; goAhead ← FALSE};
-- RETURN;
-- };----exit
-- };----sending to printer

ENDLOOP;--for each band in [0..bandcount)
IF data.device = screen THEN {
Paint: PROC[c: Graphics.Context] = {
b: Graphics.Box ← Graphics.GetBounds[c];
Graphics.SetCP[c, b.xmin, b.ymin];
GraphicsOps.DrawBitmap[self: c, bitmap: data.bitmap,
w: data.bitmap.width, -- width and height of rectangle
h: data.bitmap.height,
xorigin: 0, yorigin: data.bitmap.height]
};
TJaMGraphics.Painter[Paint];
};

Close[dev];--close all the band streams
-- IF ~NoPrinter AND goAhead THEN {PressNetDefs.CloseConnection[]; goAhead ← FALSE};
};--ShowBands

Render: PROC [data: Data, stream: BStream.BandStreamHandle] = {
debug: BOOLEAN = TRUE;
Assert: PROC[pred: BOOLEAN] = INLINE { IF debug AND NOT pred THEN ERROR };
rect: BOOLEAN ← objectRef.flags.rect;
type: BFormat.Type ← objectRef.flags.type;
y,height,bandWidth: CARDINAL;
line: LONG POINTER TO WORD;
run: LONG POINTER TO BFormat.Run;
runBump: CARDINAL;

y ← objectRef.yStart-yOffset; --Assert[y<=heraldRef.bandHeight];
height ← objectRef.height; --Assert[height<=(heraldRef.bandHeight-y)];
bandWidth ← heraldRef.bandWidth;
-- pointer to beginning of first destination scan line
line ← data.base + Inline.LongMult[y, data.rast];
run ← LOOPHOLE[runsRef]; -- pointer to first Run
-- rectangles use the same Run for each line
-- trapezoids have a new Run for each line
runBump ← IF rect THEN 0 ELSE BFormat.runSize;

SELECT type FROM
all0, all1 => { -- constant white or black
bbPointer.dstBpl ← bandWidth*bitsPerWord;
bbPointer.srcDesc.gray ← [reserved: , yOffset: 0, widthMinusOne: 0,
     heightMinusOne: 0];
bbPointer.src.word ← IF type = all1 THEN blackWord ELSE whiteWord;
bbPointer.src.bit ← 0;
bbPointer.flags.gray ← TRUE;
IF rect THEN {--BLT a rectangle in one shot!!
bbPointer.dst.word ← line + (run.xmin/bitsPerWord);
 bbPointer.dst.bit ← run.xmin MOD bitsPerWord;
 bbPointer.width ← run.xmax-run.xmin;--may be zero !!
 bbPointer.height ← height;--may be zero !!
BB.BITBLT[bbPointer];
 }--BLT a rectangle in one shot!!
ELSE {--BLT a trapezoid one line at a time
bbPointer.height ← 1;
THROUGH [0..height) DO
  bbPointer.dst.word ← line+(run.xmin/bitsPerWord);
  bbPointer.dst.bit ← run.xmin MOD bitsPerWord;
  bbPointer.width ← run.xmax-run.xmin;--may be zero !!
BB.BITBLT[bbPointer];
  run ← run + runBump;
  line ← line+bandWidth;--point to start of next line
ENDLOOP;
};--BLT a trapezoid one line at a time
}; -- constant white or black

bits => { -- specified bits (opaque), fetch each line and BLT it
bbPointer.dstBpl ← bandWidth*bitsPerWord;
bbPointer.srcDesc.srcBpl ← 0; -- don't care
bbPointer.src.word ← LOOPHOLE[lineRef];--source address
bbPointer.src.bit ← 0;
bbPointer.flags.gray ← FALSE;
bbPointer.height ← 1;
THROUGH [0..height) DO--BLT either trap or rect one line at a time
[] ← BStream.GetBand[stream, lineRef, (run.xmax-run.xmin+15)/bitsPerWord];--may fetch zero words
bbPointer.dst.word ← line+(run.xmin/bitsPerWord);
bbPointer.dst.bit ← run.xmin MOD bitsPerWord;
bbPointer.width ← run.xmax-run.xmin;--may be zero !!
BB.BITBLT[bbPointer];
run ← run + runBump;
line ← line+bandWidth;--point to start of next line
ENDLOOP;
};-- specified bits (opaque), fetch each line and BLT it

brick => { -- construct each line and BLT it
L, p, hx, hy: CARDINAL;
D: INTEGER ← 0;
bbPointer.flags.gray ← FALSE;
bbPointer.height ← 1;
L ← tBrick.L; p ← tBrick.p; D ← tBrick.D;
y ← objectRef.yStart; -- absolute, not relative y
THROUGH [0..height) DO
hy ← y MOD p;
hx ← Inline.LowHalf[Modd[(run.xmin - LONG[D]*(y/p)), L]];
CGBrickBLT.BrickBLT[bbptr: bbPointer, tBrick: tBrick,
  destLine: line, hx: hx, hy: hy,
  xmin: run.xmin, xmax: run.xmax, lineBuffer: lineRef];
run ← run + runBump;
y ← y+1;--point to start of next line absolute
line ← line+bandWidth;--point to start of next line in band buffer
ENDLOOP;
};-- construct each line and BLT it

ENDCASE => ERROR;
};--Render


CursorCode: PROC [code: CARDINAL] = {
digit, digitOffset, num: CARDINAL;
IF code > 99 THEN ERROR;
cursorPtr^ ← boxCursorArray;
wordOffset ← cursorPtr+2; num ← code;
FOR j: CARDINAL IN [0..2) DO
FOR i: CARDINAL DECREASING IN [0..1] DO --two digits only
[num, digit] ← Inline.DIVMOD[num, 10];
digitOffset ← digit*5;
cbbPtr^ ← [
dst: [word: wordOffset, bit: 5*i+3],
dstBpl: 16,
src: [word: @digitFont + digitOffset/16, bit: digitOffset MOD 16],
srcDesc: [srcBpl[64]],
width: 5, height: 6, flags: [disjoint: TRUE, dstFunc: or]];
BitBlt.BITBLT[cbbPtr];
ENDLOOP;
wordOffset ← cursorPtr+9; num ← heraldRef.bandCount-1;
ENDLOOP;
UserTerminal.SetCursorPattern[cursorPtr^];
};--CursorCode

SetFTPBoxes: PROC [] = {
UserTerminal.SetCursorPattern[ftpCursorArray];
};--SetFTPBoxes

InvertCursor: PROC [] = {
cursorPtr^ ← UserTerminal.GetCursorPattern[];
cbbPtr^ ← [ dst: [word: cursorPtr, bit: 0],
dstBpl: 16,
src: [word: @blackArray, bit: 0],
srcDesc: [srcBpl[16]],
width: 16, height: 1, flags: [disjoint: TRUE, dstFunc: xor]];
BitBlt.BITBLT[cbbPtr];
UserTerminal.SetCursorPattern[cursorPtr^];
};--InvertCursor

--START CODE FOR CGBandImageImpl

--global space handle for freeing space with Close
newSpace: Space.Handle ← Space.nullHandle;
yOffset: CARDINAL ← 0;--communicates between ShowTrap and ShowBands

-- global buffering requiring REFs
heraldRef: BFormat.HeraldRef ← uZone.NEW[BFormat.HeraldObject];
heraldSizeX2: CARDINAL ← 2*BFormat.heraldObjectSize;
objectRef: BFormat.ObjectRef ← uZone.NEW[BFormat.Object[1]];

TBrickBuffer: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF WORD];--buffer for tBrick words coming from stream
maxTBrick: CARDINAL = 400+BFormat.tBrickSize;--6400 bits maximum in a tBrick for now
brickBuffer: LONG POINTER TO TBrickBuffer ← uZone.NEW[TBrickBuffer[maxTBrick]];

RunsBuffer: TYPE = RECORD[SEQUENCE COMPUTED CARDINAL OF BFormat.Run];
RunsRef: TYPE = LONG POINTER TO RunsBuffer;
runsRef: RunsRef ← NIL; -- initialized by InitBands
runsIndex: CARDINAL ← 0; -- runs buffer index

maxL: CARDINAL = 2000;--longest permitted L for a thresholded brick
maxLx2: CARDINAL = maxL*2;--longest permitted L for a thresholded brick times 2
Scanline: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF BOOLEAN];
LineRef: TYPE = LONG POINTER TO Scanline;
lineRef: LineRef ← NIL; -- initialized by InitBands
lineIndex: CARDINAL ← 0;-- Scanline bit index

BBTable: BB.BBTableSpace;
bbPointer: BB.BBptr ← CGBrickBLT.InitializeBrickBLT[@BBTable];

--globals for CursorCode
cbbTable: BB.BBTableSpace;
cbbPtr: BB.BBptr ← BB.AlignedBBTable[@cbbTable];
digitFont: ARRAY [0..24) OF CARDINAL ← [
-- Strike-format font, densely packed, characters 6 high, 5 wide
30614B, 61474B, 167461B, 117000B,
45222B, 112441B, 512B, 57000B,
54202B, 22471B, 141062B, 57000B,
64214B, 14405B, 21111B, 157000B,
44220B, 117645B, 22110B, 57000B,
31736B, 60430B, 142063B, 117000B];

boxCursorArray: UserTerminal.CursorArray ← [
-- one bit wide border rectangle
177777B, 100001B, 100001B, 100001B,
100001B, 100001B, 100001B, 100001B,
177777B, 100001B, 100001B, 100001B,
100001B, 100001B, 100001B, 177777B];

ftpCursorArray: UserTerminal.CursorArray ← [
-- ftp boxes
177400B, 177400B, 177400B, 177400B,
177400B, 177400B, 177400B, 177400B,
377B, 377B, 377B, 377B,
377B, 377B, 377B, 377B];

blackArray: UserTerminal.CursorArray ← ALL[177777B];

wordOffset: LONG POINTER TO UserTerminal.CursorArray ← NIL;
cursorPtr: LONG POINTER TO UserTerminal.CursorArray ← uZone.NEW[UserTerminal.CursorArray];
blackWord: LONG POINTER TO CARDINAL ← uZone.NEW[CARDINAL ← 177777B];
whiteWord: LONG POINTER TO CARDINAL ← uZone.NEW[CARDINAL ← 0];

--fix up tBrick from brickBuffer
tBrick: BFormat.TBrickRef ← LOOPHOLE[brickBuffer];--common storage covering tBHead+brickBuffer
brickBuffer ← brickBuffer+BFormat.tBrickSize;


}. --CGBandImageImpl

LOG
--created 12-Nov-81 12:59:29, Pier
--large change to Cedar 2.2 and new CG, 21-Dec-81
-- large rework to include band devices like Hornet, 5-Jan-82
-- replaced NEW with pZone.NEW
--added noPrinter, fixed bug in PrinterNoGo failing to Close[dev], 14-Jan-82
--added Herald stuff, fixed all divisions(/) to roundoff correctly 15-Jan-82
-- formatted consistent with other CG modules, 19-Jan-82
--fixed potential bug in xline← using LongMult, 21-JAN-82
--fixed initialization of scanning to account for empty traps in bandfile 27-JAN-82
--changed to global NEWs and buffering, 28-JAN-82
--added single file stuff, 2/2/82
--added scan line buffer, 2/3/82
--added platemaker device, swap units 2/5/82
--added CursorCode, 2/10/82
--complete rewrite for new band format, 2/23/82
--removed run.count field, skipcount capability, 3/14/82
--changed buffers from collected to uncollected zones, 3/30/82
--removed single file stuff, 3/30/82
--swapped UnsafeStorage for Heap; changed to allow screen
-- bitmaps for Viewers, May 3, 1982
--Cedar 3.2, July 13, 1982