ImagerAISImpl.mesa
Michael Plass, July 12, 1983 1:45 pm
DIRECTORY
AIS,
Environment,
FileIO,
ImagerColor,
ImagerBasic,
IO,
Rope,
Scaled
;
ImagerAISImpl: CEDAR PROGRAM
IMPORTS AIS, FileIO, IO, Rope, Scaled
EXPORTS ImagerColor
~ BEGIN
blockHeight: NAT ~ 32;
blockWidth: NAT ~ 64;
Block: TYPE ~ REF BlockRep;
BlockRep: TYPE ~ ARRAY [0..blockHeight) OF ChunkRep;
ChunkRep: TYPE ~ PACKED ARRAY [0..blockWidth) OF [0..256);
BufferRep: TYPE ~ RECORD [
SEQUENCE numberOfChunks: NAT OF ChunkRep
];
LoadAISData: PROC [aisName: Rope.ROPE] RETURNS [reblockedAIS: ReblockedAIS] ~ TRUSTED {
text: Rope.Text ← aisName.Flatten;
ais: AIS.FRef ← AIS.OpenFile[LOOPHOLE[text], FALSE];
window: AIS.WRef ← AIS.OpenWindow[ais];
numberOfChunksAcross: NATMAX[(ais.raster.scanLength+blockWidth-1)/blockWidth, 1];
bufferRef: REF BufferRep ← NEW[BufferRep[numberOfChunksAcross]];
buffer: AIS.Buffer ← [numberOfChunksAcross*SIZE[ChunkRep], @bufferRef[0]];
rowNumber: NAT ← 0;
file: IO.STREAM ← FileIO.Open[aisName.Concat[".reblocked$"], write];
numberOfBuffers: NATMAX[numberOfChunksAcross, ais.raster.scanCount/blockHeight] + 2;
block: REF BufferSeqRep ← NEW[BufferSeqRep[numberOfBuffers]];
FlushBuffers: PROC ~ TRUSTED {
byteSize: INT ~ INT[Environment.bytesPerWord]*SIZE[BlockRep];
FOR i: NAT IN [0..numberOfChunksAcross) DO
file.UnsafePutBlock[[base: @(block[i].block[0]), startIndex: 0, stopIndexPlusOne: byteSize]];
ENDLOOP;
rowNumber ← 0;
};
IF ais.raster.bitsPerPixel # 8 THEN ERROR;
FOR i: NAT IN [0..numberOfBuffers) DO
block[i] ← [LAST[NAT], LAST[NAT], NEW[BlockRep]]
ENDLOOP;
FOR line: NAT IN [0..ais.raster.scanCount) DO
window.ReadLine[buffer, line];
FOR chunkNumber: NAT IN [0..numberOfChunksAcross) DO
block[chunkNumber].block[rowNumber] ← bufferRef[chunkNumber];
ENDLOOP;
rowNumber ← rowNumber + 1;
IF rowNumber >= blockHeight THEN FlushBuffers[];
ENDLOOP;
IF rowNumber > 0 THEN FlushBuffers[];
reblockedAIS ← NEW[ReblockedAISRep];
reblockedAIS.file ← file;
reblockedAIS.scanCount ← ais.raster.scanCount;
reblockedAIS.scanLength ← ais.raster.scanLength;
reblockedAIS.scanMode ← ais.raster.scanMode;
reblockedAIS.numberOfChunksAcross ← numberOfChunksAcross;
ais.CloseFile;
reblockedAIS.nextBufferToAllocate ← 0;
reblockedAIS.bufferSeq ← block;
};
LoadAISData: PROC [aisName: Rope.ROPE] RETURNS [file: IO.STREAM] ~ TRUSTED {
text: Rope.Text ← aisName.Flatten;
ais: AIS.FRef ← AIS.OpenFile[LOOPHOLE[text], FALSE];
window: AIS.WRef ← NIL;
AIS.OpenWindow[ais];
xPixels: NAT;
yPixels: NAT;
pixelArray: ImagerBasic.PixelArray ← NEW[ImagerBasic.PixelArrayRep];
color: ImagerBasic.SampledColor ← NEW[ImagerBasic.SampledColorRep];
curLine, curPixel, xNextLine, xNextPixel, yNextLine, yNextPixel: INTEGER;
SELECT ais.raster.scanMode FROM
ru, lu, rd, ld => {xPixels ← ais.raster.scanLength; yPixels ← ais.raster.scanCount};
ur, ul, dr, dl => {xPixels ← ais.raster.scanCount; yPixels ← ais.raster.scanLength};
ENDCASE => ERROR;
SELECT ais.raster.scanMode FROM
ru => {curLine𡤀 curPixel𡤀 xNextLine𡤀 xNextPixel𡤁 yNextLine𡤁 yNextPixel𡤀};
ul => {curLine←xPixels-1; curPixel𡤀 xNextLine←-1; xNextPixel𡤀 yNextLine𡤀 yNextPixel𡤁};
ld => {curLine←yPixels-1; curPixel←xPixels-1; xNextLine𡤀 xNextPixel←-1; yNextLine←-1; yNextPixel𡤀};
dr => {curLine𡤀 curPixel←yPixels-1; xNextLine𡤁 xNextPixel𡤀 yNextLine𡤀 yNextPixel←-1};
rd => {curLine←yPixels-1; curPixel𡤀 xNextLine𡤀 xNextPixel𡤁 yNextLine←-1; yNextPixel𡤀};
ur => {curLine𡤀 curPixel𡤀 xNextLine𡤁 xNextPixel𡤀 yNextLine𡤀 yNextPixel𡤁};
lu => {curLine𡤀 curPixel←xPixels-1; xNextLine𡤀 xNextPixel←-1; yNextLine𡤁 yNextPixel𡤀};
dl => {curLine𡤌urLine←xPixels-1; curPixel←yPixels-1; xNextLine←-1; xNextPixel𡤀 yNextLine𡤀 yNextPixel←-1};
ENDCASE => ERROR;
array ← NEW[ArrayRep[yPixels]];
FOR y: NAT IN [0..yPixels) DO
row: Row ← array[y] ← NEW[RowRep[xPixels]];
savedLine: NAT ← curLine;
savedPixel: NAT ← curPixel;
FOR x: NAT IN [0..xPixels) DO
row[x] ← window.ReadSample[curLine, curPixel];
curLine ← curLine + xNextLine;
curPixel ← curPixel + xNextPixel;
ENDLOOP;
curLine ← savedLine + yNextLine;
curPixel ← savedPixel + yNextPixel;
ENDLOOP;
ais.CloseFile;
};
ReblockedAIS: TYPE ~ REF ReblockedAISRep;
ReblockedAISRep: TYPE ~ RECORD [
file: IO.STREAM,
scanLength: NAT,
scanCount: NAT,
scanMode: AIS.ScanMode,
numberOfChunksAcross: NAT,
nextBufferToAllocate: NAT ← 0,
bufferSeq: REF BufferSeqRep
];
BufferSeqRep: TYPE ~ RECORD [
SEQUENCE length: NAT OF BufferDescriptor
];
BufferDescriptor: TYPE ~ RECORD [
xDivBlockWidth, yDivBlockHeight: NAT,
block: Block
];
AISToColor: PUBLIC PROC [aisName: Rope.ROPE] RETURNS [ImagerBasic.Color] ~ {
pixelArray: ImagerBasic.PixelArray ← NEW[ImagerBasic.PixelArrayRep];
color: ImagerBasic.SampledColor ← NEW[ImagerBasic.SampledColorRep];
reblockedAIS: ReblockedAIS ← LoadAISData[aisName];
SELECT reblockedAIS.scanMode FROM
ru, lu, rd, ld => {pixelArray.xPixels ← reblockedAIS.scanLength; pixelArray.yPixels ← reblockedAIS.scanCount};
ur, ul, dr, dl => {pixelArray.xPixels ← reblockedAIS.scanCount; pixelArray.yPixels ← reblockedAIS.scanLength};
ENDCASE => ERROR;
pixelArray.maxSampleValue ← 255;
pixelArray.samplesPerPixel ← 1;
pixelArray.get ← GetOne;
pixelArray.data ← reblockedAIS;
color.transparent ← FALSE;
color.pa ← pixelArray;
color.m ← [1, 0, 0, 0, 1, 0, identity];
color.colorMap ← $Intensity8bpp;
RETURN [color];
};
GetOne: PROC [self: ImagerBasic.PixelArray, buffer: ImagerBasic.PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ {
reblockedAIS: ReblockedAIS ← NARROW[self.data];
curBuf: BufferDescriptor;
SELECT reblockedAIS.scanMode FROM
ru => NULL;
rd => {yStart ← Scaled.FromInt[reblockedAIS.scanCount].MINUS[yStart]; yDelta ← yDelta.UMINUS};
ENDCASE => ERROR;
FOR i: NAT IN [0..nSamples) DO
y: INTEGER ← yStart.Floor;
x: INTEGER ← xStart.Floor;
IF NOT x IN [0..reblockedAIS.scanLength) THEN {
WHILE x < 0 DO x ← x + reblockedAIS.scanLength ENDLOOP;
WHILE x >= reblockedAIS.scanLength DO x ← x - reblockedAIS.scanLength ENDLOOP;
xStart.integerPart ← x;
};
IF NOT y IN [0..reblockedAIS.scanCount) THEN {
WHILE y < 0 DO y ← y + reblockedAIS.scanCount ENDLOOP;
WHILE y >= reblockedAIS.scanCount DO y ← y - reblockedAIS.scanCount ENDLOOP;
yStart.integerPart ← y;
};
IF NAT[x]/blockWidth # curBuf.xDivBlockWidth OR NAT[y]/blockHeight # curBuf.yDivBlockHeight THEN {
xDivBlockWidth: NATNAT[x]/blockWidth;
yDivBlockHeight: NATNAT[y]/blockHeight;
FOR j: NAT IN [0..reblockedAIS.bufferSeq.length) DO
curBuf ← reblockedAIS.bufferSeq[j];
IF xDivBlockWidth = curBuf.xDivBlockWidth AND yDivBlockHeight = curBuf.yDivBlockHeight THEN EXIT;
ENDLOOP;
IF xDivBlockWidth # curBuf.xDivBlockWidth OR yDivBlockHeight # curBuf.yDivBlockHeight THEN TRUSTED {
byteSize: INT ~ INT[Environment.bytesPerWord]*SIZE[BlockRep];
curBuf ← reblockedAIS.bufferSeq[reblockedAIS.nextBufferToAllocate];
curBuf.xDivBlockWidth ← xDivBlockWidth;
curBuf.yDivBlockHeight ← yDivBlockHeight;
reblockedAIS.file.SetIndex[(INT[yDivBlockHeight]*reblockedAIS.numberOfChunksAcross+xDivBlockWidth)*(INT[Environment.bytesPerWord]*SIZE[BlockRep])];
[] ← reblockedAIS.file.UnsafeGetBlock[[base: @(curBuf.block[0]), startIndex: 0, stopIndexPlusOne: byteSize]];
reblockedAIS.bufferSeq[reblockedAIS.nextBufferToAllocate] ← curBuf;
reblockedAIS.nextBufferToAllocate ← reblockedAIS.nextBufferToAllocate + 1;
IF reblockedAIS.nextBufferToAllocate >= reblockedAIS.bufferSeq.length THEN reblockedAIS.nextBufferToAllocate ← 0;
};
};
buffer[i] ← curBuf.block[NAT[y] MOD blockHeight][NAT[x] MOD blockWidth];
xStart ← xStart.PLUS[xDelta];
yStart ← yStart.PLUS[yDelta];
ENDLOOP;
};
END.