DitherAISImple.mesa
Mik Lamming February 6, 1984 11:15:26 am PST PST PST PST PST PST PST PST
DIRECTORY
AIS, DitherAIS, FS, Rope;
DitherAISImpl: PROGRAM
IMPORTS AIS, FS
EXPORTS DitherAIS = BEGIN
OPEN DitherAIS;
Squash: PUBLIC PROCEDURE [redFn, greenFn, blueFn, rgbFn:Rope.ROPE, map:UserMapProc] = {
Transforms the three AIS files red,green and blue into the single AIS file: rgb using the user supplied map procedure and applying Floyd-Steinberg error distribution.
redFD, greenFD, blueFD, rgbFD:AIS.FRef;
temp, this, next:PixelBuf; -- 'this' holds current line's data, 'next - the one below
r:AIS.Raster;
redW, blueW, greenW, rgbW:AIS.WRef;
scan, top, bottom, left, right:CARDINAL;
Open the input files and get hold of the raster info. for use in generating the rgb ouput file
redFD ← AIS.OpenFile[redFn];
redW ← AIS.OpenWindow[redFD];
greenFD ← AIS.OpenFile[greenFn];
greenW ← AIS.OpenWindow[greenFD];
blueFD ← AIS.OpenFile[blueFn];
blueW ← AIS.OpenWindow[blueFD];
Create the output file
r ← AIS.ReadRaster[redFD];
[] ← AIS.DeleteFile[rgbFn ! FS.Error => CONTINUE];
rgbFD ← AIS.CreateFile[name:rgbFn, raster:r];
rgbW ← AIS.OpenWindow[rgbFD];
Create two working buffers for scan lines
[top, bottom, left, right] ← AIS.GetWindowParams[redW];
this ← NEW[PixelBufRec[right+2]]; -- make it a bit bigger to catch error propogation
next ← NEW[PixelBufRec[right+2]];
initialise the 'next' buffer with the first scan line
ReadRGB[redW, greenW, blueW, left, right, 1, next];
FOR scan IN [top..bottom] DO
advance the scan line buffers to the next line
temp ← this; this ← next; next ← temp;
IF scan < bottom THEN
ReadRGB[redW, greenW, blueW, left, right, scan+1, next];
SquashScan[this, next, left,right, map];
Writergb[rgbW, left, right, scan, this];
ENDLOOP;
AIS.CloseWindow[redW];
AIS.CloseWindow[blueW];
AIS.CloseWindow[greenW];
AIS.CloseWindow[rgbW];
AIS.CloseFile[redFD];
AIS.CloseFile[blueFD];
AIS.CloseFile[greenFD];
AIS.CloseFile[rgbFD];
};
Stretch: PUBLIC PROCEDURE [redFn, greenFn, blueFn, rgbFn:Rope.ROPE, unMap:UserUnmapProc] = {
Takes a dithered file rgbFn and cretates three separations using the unMap procedure
redFD, greenFD, blueFD, rgbFD:AIS.FRef;
raster:AIS.Raster;
redW, blueW, greenW, rgbW:AIS.WRef;
scan, pixel, top, bottom, left, right:CARDINAL;
r,g,b:CARDINAL;
Open the input file and get hold of the raster info. for use in generating the ouput files
rgbFD ← AIS.OpenFile[name:rgbFn];
rgbW ← AIS.OpenWindow[rgbFD];
raster ← AIS.ReadRaster[rgbFD];
[] ← AIS.DeleteFile[redFn];
redFD ← AIS.CreateFile[name:redFn, raster:raster];
redW ← AIS.OpenWindow[redFD];
[] ← AIS.DeleteFile[greenFn];
greenFD ← AIS.CreateFile[name:greenFn, raster:raster];
greenW ← AIS.OpenWindow[greenFD];
[] ← AIS.DeleteFile[blueFn];
blueFD ← AIS.CreateFile[name:blueFn, raster:raster];
blueW ← AIS.OpenWindow[blueFD];
[top, bottom, left, right] ← AIS.GetWindowParams[rgbW];
FOR scan IN [top..bottom] DO
FOR pixel IN [left..right] DO
[r,g,b] ← unMap[AIS.ReadSample[rgbW, scan, pixel]];
AIS.WriteSample[redW, r, scan, pixel];
AIS.WriteSample[greenW, g, scan, pixel];
AIS.WriteSample[blueW, b, scan, pixel];
ENDLOOP;
ENDLOOP;
AIS.CloseWindow[redW];
AIS.CloseWindow[blueW];
AIS.CloseWindow[greenW];
AIS.CloseWindow[rgbW];
AIS.CloseFile[redFD];
AIS.CloseFile[blueFD];
AIS.CloseFile[greenFD];
AIS.CloseFile[rgbFD];
};
SquashScan: PUBLIC PROCEDURE [this, next:PixelBuf, left,right:CARDINAL, map:UserMapProc] = {
Processes the pixel buffer 'this' using the user supplied map procedure 'map' to fill in the rgb field in each pixel of 'this' and modifies the contents of the buffer 'next' using Floyd-Steinberg error distribution
redError, greenError, blueError: INTEGER;
FOR pixel:CARDINAL IN [left..right] DO
[this.data[pixel].rgb, redError, greenError, blueError]
← map[this.data[pixel].red, this.data[pixel].green, this.data[pixel].blue];
use Floyd-Steinberg to distribute error to right and next line
this.data[pixel+1].red ← this.data[pixel+1].red + redError*3/8;
this.data[pixel+1].green ← this.data[pixel+1].green + greenError*3/8;
this.data[pixel+1].blue ← this.data[pixel+1].blue + blueError*3/8;
next.data[pixel].red ← next.data[pixel].red + redError*3/8;
next.data[pixel].green ← next.data[pixel].green + greenError*3/8;
next.data[pixel].blue ← next.data[pixel].blue + blueError*3/8;
next.data[pixel+1].red ← next.data[pixel+1].red + redError/4;
next.data[pixel+1].green ← next.data[pixel+1].green + greenError/4;
next.data[pixel+1].blue ← next.data[pixel+1].blue + blueError/4;
ENDLOOP
};

ReadRGB: PROCEDURE [r,g,b:AIS.WRef, left, right, scan:CARDINAL, buf:PixelBuf] = {
FOR i:CARDINAL IN [left..right] DO
buf.data[i].red ← AIS.ReadSample[r, scan, i];
buf.data[i].green ← AIS.ReadSample[g, scan, i];
buf.data[i].blue ← AIS.ReadSample[b, scan, i];
ENDLOOP;
};
Writergb: PROCEDURE [rgb:AIS.WRef, left, right, scan:CARDINAL, buf:PixelBuf] = {
FOR i:CARDINAL IN [left..right] DO
AIS.WriteSample[rgb, buf.data[i].rgb, scan, i];
ENDLOOP;
};
END.