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. ุDitherAISImple.mesa Mik Lamming February 6, 1984 11:15:26 am PST PST PST PST PST PST PST PST 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. Open the input files and get hold of the raster info. for use in generating the rgb ouput file Create the output file Create two working buffers for scan lines initialise the 'next' buffer with the first scan line advance the scan line buffers to the next line Takes a dithered file rgbFn and cretates three separations using the unMap procedure Open the input file and get hold of the raster info. for use in generating the ouput files 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 use Floyd-Steinberg to distribute error to right and next line สn– "Mesa" style˜Jšœ™JšœH™HJ™šฯk ˜ Jšœ œ˜—J˜šฯn œœ˜Jšœ˜Jšœ ˜Jšœ ˜˜Jšžœ#œ˜W™ฆJšœœ˜'Jšœฯc:˜UJšœœ˜ Jšœœ˜#Jšœœ˜(J˜J™^Jšœ˜Jšœ˜Jšœ ˜ Jšœ!˜!Jšœ˜Jšœ˜J˜J™Jšœ˜Jšœœœ œ˜2Jšœ-˜-Jšœ˜J˜J™)Jšœ7˜7Jšœ"Ÿ2˜TJšœ!˜!J˜J™5Jšœ3˜3šœ˜J™.Jšœ(˜(šœœ˜Jšœ8˜8—Jšœ(˜(Jšœ(˜(Jš˜—Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜J˜—Jšžœœ#œ˜\J™T™Jšœœ˜'Jšœœ˜Jšœœ˜#Jšœ&œ˜/Jšœœ˜J˜J™ZJšœ!˜!Jšœ˜Jšœœ˜J˜J˜Jšœ˜Jšœ2˜2Jšœ˜Jšœ˜Jšœ6˜6Jšœ"˜"Jšœ˜Jšœ4˜4Jšœ ˜ Jšœ7˜7J˜šœ˜šœœ˜Jšœœ!˜4Jšœ#˜&Jšœ%˜(Jšœ$˜'Jš˜—Jš˜—Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—J˜—procšž œœ" œœ˜\Kšœึ™ึKšœ!œ˜)šœœœ˜&šœ7˜7JšœK˜K—J˜J™>Jšœ?˜?JšœE˜EJšœB˜BJšœ;˜;JšœA˜AJšœ>˜>Jšœ=˜=JšœC˜CJšœ@˜@Jš˜—J˜—š œžœ œœœ˜Ršœœœ˜"Jšœœ˜-Jšœœ˜/Jšœœ˜.Jšœ˜—J˜—š žœ œžœžœœ˜Pšœœœ˜"Jšœ,˜/Jšœ˜—J˜—J˜Jšœ˜——…—Œา