internal override void Initialize(Bitmap source, bool isInUse) { // this must be the first line to prevent disposing source if next lines fail isSourceCloned = isInUse; PixelFormat origPixelFormat = source.PixelFormat; PixelFormat pixelFormat = origPixelFormat.HasAlpha() || origPixelFormat.IsIndexed() && source.Palette.Entries.Any(c => c.A != Byte.MaxValue) ? PixelFormat.Format32bppPArgb : PixelFormat.Format24bppRgb; targetBitmap = new Bitmap(Size.Width, Size.Height, pixelFormat); targetBitmapData = targetBitmap.GetReadWriteBitmapData(); // Locking on source image to avoid "bitmap region is already locked" if the UI is painting the image when we clone it. // This works this way because UI can repaint the image any time and is also locks the image for that period. // Another solution could be if we used a clone of the original image but it is better to avoid using multiple clones. if (isInUse) { // if image is in use (in the view of this VM) we lock it only for a short time to prevent the UI freezing lock (source) sourceBitmap = source.CloneCurrentFrame(); } else { // If no direct use could be detected using a long-term lock to spare a clone. // It is still needed because the image still can be used in the main V/VM. Monitor.Enter(source); sourceBitmap = source; } sourceBitmapData = sourceBitmap.GetReadableBitmapData(); }
protected static void GenerateAlphaGradient(IReadWriteBitmapData bitmapData) { var firstRow = bitmapData.FirstRow; float ratio = 255f / (bitmapData.Width / 6f); float limit = bitmapData.Width / 6f; for (int x = 0; x < bitmapData.Width; x++) { // red -> yellow if (x < limit) { firstRow[x] = new Color32(255, (x * ratio).ClipToByte(), 0); } // yellow -> green else if (x < limit * 2) { firstRow[x] = new Color32((255 - (x - limit) * ratio).ClipToByte(), 255, 0); } // green -> cyan else if (x < limit * 3) { firstRow[x] = new Color32(0, 255, ((x - limit * 2) * ratio).ClipToByte()); } // cyan -> blue else if (x < limit * 4) { firstRow[x] = new Color32(0, (255 - (x - limit * 3) * ratio).ClipToByte(), 255); } // blue -> magenta else if (x < limit * 5) { firstRow[x] = new Color32(((x - limit * 4) * ratio).ClipToByte(), 0, 255); } // magenta -> red else { firstRow[x] = new Color32(255, 0, (255 - (x - limit * 5) * ratio).ClipToByte()); } } if (bitmapData.Height < 2) { return; } var row = bitmapData[1]; ratio = 255f / bitmapData.Height; do { byte a = (255 - row.Index * ratio).ClipToByte(); for (int x = 0; x < bitmapData.Width; x++) { row[x] = Color32.FromArgb(a, firstRow[x]); } } while (row.MoveNextRow()); }
public void CopyToClippedTest(PixelFormat pixelFormat) { using IReadableBitmapData src = Icons.Information.ExtractBitmap(new Size(256, 256)).ConvertPixelFormat(pixelFormat).GetReadableBitmapData(); Size targetSize = new Size(128, 128); using IReadWriteBitmapData dst = BitmapDataFactory.CreateBitmapData(targetSize, pixelFormat); new PerformanceTest { CpuAffinity = null, Iterations = 10_000 }
internal override void SetCompleted() { sourceBitmapData?.Dispose(); sourceBitmapData = null; if (isSourceCloned) { sourceBitmap?.Dispose(); } else if (sourceBitmap != null) { Monitor.Exit(sourceBitmap); } sourceBitmap = null; targetBitmapData?.Dispose(); targetBitmapData = null; base.SetCompleted(); }
internal override void SetCompleted() { BitmapData?.Dispose(); BitmapData = null; base.SetCompleted(); }
internal override void Initialize(Bitmap source, bool isInUse) { lock (source) result = source.CloneCurrentFrame(); BitmapData = result.GetReadWriteBitmapData(); }
internal ClippedBitmapData(IBitmapData source, Rectangle clippingRegion) { if (source == null) { throw new ArgumentNullException(nameof(source)); } region = clippingRegion; // source is already clipped: unwrapping to prevent tiered nesting (not calling Unwrap because other types should not be extracted here) if (source is ClippedBitmapData parent) { BitmapData = parent.BitmapData; region.Offset(parent.region.Location); region.Intersect(parent.region); } else { BitmapData = source; region.Intersect(new Rectangle(Point.Empty, source.GetSize())); } if (region.IsEmpty) { throw new ArgumentOutOfRangeException(nameof(clippingRegion), PublicResources.ArgumentOutOfRange); } bitmapDataType = BitmapData switch { IBitmapDataInternal _ => BitmapDataType.Internal, IReadWriteBitmapData _ => BitmapDataType.ReadWrite, IReadableBitmapData _ => BitmapDataType.Readable, IWritableBitmapData _ => BitmapDataType.Writable, _ => BitmapDataType.None }; PixelFormat = BitmapData.PixelFormat; BackColor = BitmapData.BackColor; AlphaThreshold = BitmapData.AlphaThreshold; Palette = BitmapData.Palette; int bpp = PixelFormat.ToBitsPerPixel(); int maxRowSize = (region.Width * bpp) >> 3; RowSize = region.Left > 0 // Any clipping from the left disables raw access because ReadRaw/WriteRaw offset depends on size of T, // which will fail for any T whose size is not the same as the actual pixel size ? 0 // Even one byte padding is disabled to protect the right edge of a region by default : Math.Min(source.RowSize, maxRowSize); if (bpp >= 8 || RowSize < maxRowSize) { return; } // 1/4bpp: Adjust RowSize if needed // right edge: if not at byte boundary but that is the right edge of the original image, then we allow including padding if (PixelFormat.IsAtByteBoundary(region.Width) && region.Right == BitmapData.Width) { RowSize++; } }