<> <> <<>> DIRECTORY AIS USING [CloseFile, CloseWindow, CreateFile, DeleteFile, FRef, GetWindowParams, OpenFile, OpenWindow, Raster, RasterPart, ReadRaster, ReadSample, WRef, WriteSample], ConvertUnsafe USING [AppendRope], DitherAIS, Rope USING [ROPE]; DitherAISImpl: PROGRAM IMPORTS AIS, ConvertUnsafe EXPORTS DitherAIS = BEGIN OPEN DitherAIS; Squash: PUBLIC PROCEDURE [redFn, greenFn, blueFn, rgbFn:Rope.ROPE, map:UserMapProc] = { <> redString: LONG STRING _ [30]; greenString: LONG STRING _ [30]; blueString: LONG STRING _ [30]; rgbString: LONG STRING _ [30]; redFD, greenFD, blueFD, rgbFD:AIS.FRef; temp, this, next:PixelBuf; -- 'this' holds current line's data, 'next - the one below r:AIS.RasterPart; redW, blueW, greenW, rgbW:AIS.WRef; scan, top, bottom, left, right:CARDINAL; <> ConvertUnsafe.AppendRope[redString, redFn]; ConvertUnsafe.AppendRope[greenString, greenFn]; ConvertUnsafe.AppendRope[blueString, blueFn]; redFD _ AIS.OpenFile[redString]; redW _ AIS.OpenWindow[redFD]; greenFD _ AIS.OpenFile[greenString]; greenW _ AIS.OpenWindow[greenFD]; blueFD _ AIS.OpenFile[blueString]; blueW _ AIS.OpenWindow[blueFD]; <> AIS.ReadRaster[redFD, @r]; ConvertUnsafe.AppendRope[rgbString, rgbFn]; [] _ AIS.DeleteFile[rgbString]; rgbFD _ AIS.CreateFile[name:rgbString, raster:@r, overwrite:TRUE]; 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] = { <> <<>> redString: LONG STRING _ [30]; greenString: LONG STRING _ [30]; blueString: LONG STRING _ [30]; rgbString: LONG STRING _ [30]; redFD, greenFD, blueFD, rgbFD:AIS.FRef; raster:AIS.RasterPart; redW, blueW, greenW, rgbW:AIS.WRef; scan, pixel, top, bottom, left, right:CARDINAL; r,g,b:CARDINAL; <> ConvertUnsafe.AppendRope[redString, redFn]; ConvertUnsafe.AppendRope[greenString, greenFn]; ConvertUnsafe.AppendRope[blueString, blueFn]; ConvertUnsafe.AppendRope[rgbString, rgbFn]; rgbFD _ AIS.OpenFile[name:rgbString]; rgbW _ AIS.OpenWindow[rgbFD]; AIS.ReadRaster[rgbFD, @raster]; [] _ AIS.DeleteFile[redString]; redFD _ AIS.CreateFile[name:redString, raster:@raster, overwrite:TRUE]; redW _ AIS.OpenWindow[redFD]; [] _ AIS.DeleteFile[greenString]; greenFD _ AIS.CreateFile[name:greenString, raster:@raster, overwrite:TRUE]; greenW _ AIS.OpenWindow[greenFD]; [] _ AIS.DeleteFile[blueString]; blueFD _ AIS.CreateFile[name:blueString, raster:@raster, overwrite:TRUE]; 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.