/// <summary> /// quantizes the specified image using a floyd-steinberg error diffusion dithering /// </summary> private unsafe void QuantizeFloydSteinberg(ColorBgra *pixels, int width, int height) { if (_octree == null) { return; } int index = 0; ColorBgra col; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++, index++) { col = _octree.Table[_octree.GetOctreeIndex(pixels[index])]; int er = (int)pixels[index].R - (int)col.R, eg = (int)pixels[index].G - (int)col.G, eb = (int)pixels[index].B - (int)col.B; #region error matrix for (int i = 0; i < 2; i++) { int iy = i + y; if (iy >= 0 && iy < height) { for (int j = -1; j < 2; j++) { int jx = j + x; if (jx >= 0 && jx < width) { //load error dispersion from matrix int w = floydsteinbergmatrix[i][j + 1]; if (w != 0) { int k = jx + iy * width; pixels[k].Red += (er * w) / floydsteinbergsum; pixels[k].Green += (eg * w) / floydsteinbergsum; pixels[k].Blue += (eb * w) / floydsteinbergsum; } } } } #endregion } pixels[index] = col; } } }
/// <summary> /// writes the image to the specified stream /// </summary> public override void Write(Stream str) { if (str == null) { throw new ArgumentNullException("str"); } //write header BITMAPINFOHEADER header = new BITMAPINFOHEADER( _bitmap.Size, _bitsperpixel, this.SizeInBytes, (1 << _bitsperpixel) & 0xFF); header.Write(str); using (SimpleWriter wrt = new SimpleWriter(str)) { #region write palette foreach (ColorBgra value in _octree.Table) { wrt.Write(value.B); wrt.Write(value.G); wrt.Write(value.R); wrt.Write((byte)0); //reserved } #endregion #region write indexed data //write bitmap BitmapData bd = _bitmap.LockBits( new Rectangle(Point.Empty, _bitmap.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); ColorBgra *scan0 = (ColorBgra *)bd.Scan0; //write indexed data int indexmask = (1 << _bitsperpixel) - 1, indexdata = 0; scan0 += bd.Width * bd.Height; for (int y = 0; y < bd.Height; y++) { scan0 -= bd.Width; int indexpos = 8 - _bitsperpixel; indexdata = 0; for (int x = 0; x < bd.Width; x++) { indexdata |= (_octree.GetOctreeIndex(scan0[x]) & indexmask) << indexpos; if (indexpos % 8 == 0) { indexpos += (16 - _bitsperpixel); } else { indexpos -= _bitsperpixel; } if (indexpos >= 32) { wrt.Write(indexdata); indexdata = 0; indexpos -= 32; } } if (indexpos != (8 - _bitsperpixel)) { wrt.Write(indexdata); } } ANDMap.WriteToStream(bd, wrt); #endregion _bitmap.UnlockBits(bd); } }