static void Clear32Bpp(IAsyncContext context, IBitmapDataInternal bitmapData, Color32 color, int width) { int longWidth = bitmapData.RowSize >> 3; // writing as longs if (longWidth > 0) { Color32 rawColor = bitmapData.PixelFormat switch { PixelFormat.Format32bppPArgb => color.ToPremultiplied(), PixelFormat.Format32bppRgb => color.BlendWithBackground(bitmapData.BackColor), _ => color, }; uint argb = (uint)rawColor.ToArgb(); ClearRaw(context, bitmapData, longWidth, ((ulong)argb << 32) | argb); } // handling the rest (can be either the last column if width is odd, or even the whole content if RowSize is 0) int left = longWidth << 1; if (left < width && !context.IsCancellationRequested) { ClearDirectFallback(context, bitmapData, color, left); } }
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)); }
public override unsafe void DoSetColor32(int x, Color32 c) { if (c.A != Byte.MaxValue) { c = c.A >= BitmapData.AlphaThreshold ? c.BlendWithBackground(BitmapData.BackColor) : c.A < 128 ? c : default; } ((Color16Argb1555 *)Address)[x] = new Color16Argb1555(c); }
public override unsafe void DoSetColor32(int x, Color32 c) // performing the quantization to RGB555 before setting as RGB888 => ((Color24 *)Address)[x] = new Color24(new Color16Rgb555(c.A == Byte.MaxValue ? c : c.BlendWithBackground(BitmapData.BackColor)).ToColor32());
public override void DoSetColor32(int x, Color32 c) => Row[x] = new Color48(c.A == Byte.MaxValue ? c : c.BlendWithBackground(BitmapData.BackColor));
public override unsafe void DoSetColor32(int x, Color32 c) => ((Color16Rgb565 *)Address)[x] = new Color16Rgb565(c.A == Byte.MaxValue ? c : c.BlendWithBackground(BitmapData.BackColor));
public override unsafe void DoSetColor32(int x, Color32 c) => ((Color48 *)Address)[x] = (c.A == Byte.MaxValue ? c : c.BlendWithBackground(BitmapData.BackColor)).ToColor48PlatformDependent();
private void PerformDrawWithDithering(IQuantizingSession quantizingSession, IDitheringSession ditheringSession) { IBitmapDataInternal source = Source; IBitmapDataInternal target = Target; Point sourceLocation = SourceRectangle.Location; Point targetLocation = TargetRectangle.Location; int sourceWidth = SourceRectangle.Width; // Sequential processing if (ditheringSession.IsSequential || SourceRectangle.Width < parallelThreshold >> ditheringScale) { context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height); for (int y = 0; y < SourceRectangle.Height; y++) { if (context.IsCancellationRequested) { return; } ProcessRow(y); context.Progress?.Increment(); } return; } // Parallel processing ParallelHelper.For(context, DrawingOperation.ProcessingPixels, 0, SourceRectangle.Height, ProcessRow); #region Local Methods void ProcessRow(int y) { IDitheringSession session = ditheringSession; IBitmapDataRowInternal rowSrc = source.DoGetRow(sourceLocation.Y + y); IBitmapDataRowInternal rowDst = target.DoGetRow(targetLocation.Y + y); int offsetSrc = sourceLocation.X; int offsetDst = targetLocation.X; byte alphaThreshold = quantizingSession.AlphaThreshold; int width = sourceWidth; for (int x = 0; x < width; x++) { Color32 colorSrc = rowSrc.DoGetColor32(x + offsetSrc); // fully solid source: overwrite if (colorSrc.A == Byte.MaxValue) { rowDst.DoSetColor32(x + offsetDst, session.GetDitheredColor(colorSrc, x, y)); continue; } // fully transparent source: skip if (colorSrc.A == 0) { continue; } // source here has a partial transparency: we need to read the target color int pos = x + offsetDst; Color32 colorDst = rowDst.DoGetColor32(pos); // non-transparent target: blending if (colorDst.A != 0) { colorSrc = colorDst.A == Byte.MaxValue // target pixel is fully solid: simple blending ? colorSrc.BlendWithBackground(colorDst) // both source and target pixels are partially transparent: complex blending : colorSrc.BlendWith(colorDst); } // overwriting target color only if blended color has high enough alpha if (colorSrc.A < alphaThreshold) { continue; } rowDst.DoSetColor32(pos, session.GetDitheredColor(colorSrc, x, y)); } } #endregion }
internal void PerformDrawDirect() { IBitmapDataInternal source = Source; IBitmapDataInternal target = Target; Point sourceLocation = SourceRectangle.Location; Point targetLocation = TargetRectangle.Location; int sourceWidth = SourceRectangle.Width; // Sequential processing if (SourceRectangle.Width < parallelThreshold) { if (Target.IsFastPremultiplied()) { context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height); for (int y = 0; y < SourceRectangle.Height; y++) { if (context.IsCancellationRequested) { return; } ProcessRowPremultiplied(y); context.Progress?.Increment(); } } else { context.Progress?.New(DrawingOperation.ProcessingPixels, SourceRectangle.Height); for (int y = 0; y < SourceRectangle.Height; y++) { if (context.IsCancellationRequested) { return; } ProcessRowStraight(y); context.Progress?.Increment(); } } return; } // Parallel processing Action <int> processRow = Target.IsFastPremultiplied() ? ProcessRowPremultiplied : (Action <int>)ProcessRowStraight; ParallelHelper.For(context, DrawingOperation.ProcessingPixels, 0, SourceRectangle.Height, processRow); #region Local Methods void ProcessRowStraight(int y) { IBitmapDataRowInternal rowSrc = source.DoGetRow(sourceLocation.Y + y); IBitmapDataRowInternal rowDst = target.DoGetRow(targetLocation.Y + y); int offsetSrc = sourceLocation.X; int offsetDst = targetLocation.X; byte alphaThreshold = target.AlphaThreshold; int width = sourceWidth; for (int x = 0; x < width; x++) { Color32 colorSrc = rowSrc.DoGetColor32(x + offsetSrc); // fully solid source: overwrite if (colorSrc.A == Byte.MaxValue) { rowDst.DoSetColor32(x + offsetDst, colorSrc); continue; } // fully transparent source: skip if (colorSrc.A == 0) { continue; } // source here has a partial transparency: we need to read the target color int pos = x + offsetDst; Color32 colorDst = rowDst.DoGetColor32(pos); // non-transparent target: blending if (colorDst.A != 0) { colorSrc = colorDst.A == Byte.MaxValue // target pixel is fully solid: simple blending ? colorSrc.BlendWithBackground(colorDst) // both source and target pixels are partially transparent: complex blending : colorSrc.BlendWith(colorDst); } // overwriting target color only if blended color has high enough alpha if (colorSrc.A < alphaThreshold) { continue; } rowDst.DoSetColor32(pos, colorSrc); } } void ProcessRowPremultiplied(int y) { IBitmapDataRowInternal rowSrc = source.DoGetRow(sourceLocation.Y + y); IBitmapDataRowInternal rowDst = target.DoGetRow(targetLocation.Y + y); int offsetSrc = sourceLocation.X; int offsetDst = targetLocation.X; int width = sourceWidth; for (int x = 0; x < width; x++) { Color32 colorSrc = rowSrc.DoGetColor32Premultiplied(x + offsetSrc); // fully solid source: overwrite if (colorSrc.A == Byte.MaxValue) { rowDst.DoSetColor32Premultiplied(x + offsetDst, colorSrc); continue; } // fully transparent source: skip if (colorSrc.A == 0) { continue; } // source here has a partial transparency: we need to read the target color int pos = x + offsetDst; Color32 colorDst = rowDst.DoGetColor32Premultiplied(pos); // non-transparent target: blending if (colorDst.A != 0) { colorSrc = colorSrc.BlendWithPremultiplied(colorDst); } rowDst.DoSetColor32Premultiplied(pos, colorSrc); } } #endregion }