<> <> <<>> 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] = { <> 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; <> redFD _ AIS.OpenFile[redFn]; redW _ AIS.OpenWindow[redFD]; greenFD _ AIS.OpenFile[greenFn]; greenW _ AIS.OpenWindow[greenFD]; blueFD _ AIS.OpenFile[blueFn]; blueW _ AIS.OpenWindow[blueFD]; <> r _ AIS.ReadRaster[redFD]; [] _ AIS.DeleteFile[rgbFn ! FS.Error => CONTINUE]; rgbFD _ AIS.CreateFile[name:rgbFn, raster:r]; rgbW _ AIS.OpenWindow[rgbFD]; <> [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]]; <> ReadRGB[redW, greenW, blueW, left, right, 1, next]; FOR scan IN [top..bottom] DO <> 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] = { <> <<>> 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; <> 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] = { <> 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]; <> 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.