private Palette?InitializePalette(IReadableBitmapData source, IAsyncContext context) { using var alg = new TAlg(); alg.Initialize(quantizer.maxColors, source); int width = source.Width; IReadableBitmapDataRow row = source.FirstRow; context.Progress?.New(DrawingOperation.InitializingQuantizer, source.Height); do { if (context.IsCancellationRequested) { return(null); } // TODO: parallel if possible for (int x = 0; x < width; x++) { Color32 c = row[x]; // handling alpha including full transparency if (c.A != Byte.MaxValue) { c = c.A < quantizer.alphaThreshold ? default : c.BlendWithBackground(quantizer.backColor); } alg.AddColor(c); } context.Progress?.Increment(); } while (row.MoveNextRow()); Color32[]? palette = alg.GeneratePalette(context); return(context.IsCancellationRequested ? null : new Palette(palette !, quantizer.backColor, quantizer.alphaThreshold)); }
private static void WriteRawBitmap(Bitmap bitmap, BinaryWriter bw) { Size size = bitmap.Size; bw.Write(size.Width); bw.Write(size.Height); PixelFormat pixelFormat = bitmap.PixelFormat; bw.Write((int)pixelFormat); if (pixelFormat.ToBitsPerPixel() <= 8) { Color[] palette = bitmap.Palette.Entries; bw.Write(palette.Length); foreach (Color color in palette) { bw.Write(color.ToArgb()); } } using (IReadableBitmapData data = bitmap.GetReadableBitmapData()) { int width = data.RowSize >> 2; IReadableBitmapDataRow row = data.FirstRow; do { for (int x = 0; x < width; x++) { bw.Write(row.ReadRaw <int>(x)); } } while (row.MoveNextRow()); } }
protected static void AssertAreEqual(IReadableBitmapData source, IReadableBitmapData target, bool allowDifferentPixelFormats = false, Rectangle sourceRectangle = default, Point targetLocation = default) { if (sourceRectangle == default) { sourceRectangle = new Rectangle(Point.Empty, source.GetSize()); } Assert.AreEqual(sourceRectangle.Size, target.GetSize()); if (!allowDifferentPixelFormats) { Assert.AreEqual(source.PixelFormat, target.PixelFormat); } IReadableBitmapDataRow rowSrc = source[sourceRectangle.Y]; IReadableBitmapDataRow rowDst = target[targetLocation.Y]; bool tolerantCompare = source.GetType() != target.GetType() && source.PixelFormat.ToBitsPerPixel() > 32; for (int y = 0; y < sourceRectangle.Height; y++) { if (tolerantCompare) { for (int x = 0; x < sourceRectangle.Width; x++) { Color32 c1 = rowSrc[x + sourceRectangle.X]; Color32 c2 = rowDst[x + targetLocation.X]; // this is faster than the asserts below if (c1.A != c2.A || Math.Abs(c1.R - c2.R) > 5 || Math.Abs(c1.G - c2.G) > 5 || Math.Abs(c1.B - c2.B) > 5) { Assert.Fail($"Diff at {x}; {rowSrc.Index}: {c1} vs. {c2}"); } //Assert.AreEqual(c1.A, c2.A, $"Diff at {x}; {rowSrc.Index}"); //Assert.That(() => Math.Abs(c1.R - c2.R), new LessThanOrEqualConstraint(1), $"Diff at {x}; {rowSrc.Index}"); //Assert.That(() => Math.Abs(c1.G - c2.G), new LessThanOrEqualConstraint(1), $"Diff at {x}; {rowSrc.Index}"); //Assert.That(() => Math.Abs(c1.B - c2.B), new LessThanOrEqualConstraint(1), $"Diff at {x}; {rowSrc.Index}"); } continue; } for (int x = 0; x < sourceRectangle.Width; x++) { Assert.AreEqual(rowSrc[x + sourceRectangle.X], rowDst[x + targetLocation.X], $"Diff at {x}; {rowSrc.Index}"); } } while (rowSrc.MoveNextRow() && rowDst.MoveNextRow()) { ; } }
private void PreprocessOddRow(int y) { // Odd rows are preprocessed so we don't need to complicate the IDitheringSession interface with processing path. // It is not even a significant overhead unless not every pixel is queried (eg. DrawInto with clipped region). IReadableBitmapDataRow row = source[y]; // processing odd rows from right to left for (int x = ImageWidth - 1; x >= 0; x--) { preprocessedResults[x] = DoErrorDiffusion(row[x], x, y); } }
public void ToGrayscaleTest() { using Bitmap bmp = Icons.Information.ExtractBitmap(new Size(256, 256)); new PerformanceTest { Iterations = 100, CpuAffinity = null } .AddCase(() => { using var result = new Bitmap(bmp.Width, bmp.Height); using (Graphics g = Graphics.FromImage(result)) { // Grayscale color matrix var colorMatrix = new ColorMatrix(new float[][] { new float[] { ColorExtensions.RLum, ColorExtensions.RLum, ColorExtensions.RLum, 0, 0 }, new float[] { ColorExtensions.GLum, ColorExtensions.GLum, ColorExtensions.GLum, 0, 0 }, new float[] { ColorExtensions.BLum, ColorExtensions.BLum, ColorExtensions.BLum, 0, 0 }, new float[] { 0, 0, 0, 1, 0 }, new float[] { 0, 0, 0, 0, 1 } }); using (var attrs = new ImageAttributes()) { attrs.SetColorMatrix(colorMatrix); g.DrawImage(bmp, new Rectangle(0, 0, result.Width, result.Height), 0, 0, result.Width, result.Height, GraphicsUnit.Pixel, attrs); } } }, "Graphics.DrawImage(..., ImageAttributes)") .AddCase(() => { using var result = new Bitmap(bmp.Width, bmp.Height); using IReadableBitmapData src = bmp.GetReadableBitmapData(); using IWritableBitmapData dst = result.GetWritableBitmapData(); IReadableBitmapDataRow rowSrc = src.FirstRow; IWritableBitmapDataRow rowDst = dst.FirstRow; do { for (int x = 0; x < src.Width; x++) { rowDst[x] = rowSrc[x].ToGray(); } } while (rowSrc.MoveNextRow() && rowDst.MoveNextRow()); }, "Sequential processing") .AddCase(() => { using var result = bmp.ToGrayscale(); }, "ImageExtensions.ToGrayscale") .DoTest() .DumpResults(Console.Out); }