// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // namespace ImageProcessorCore { using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; /// /// Provides per-pixel access to generic pixels. /// /// The pixel format. /// The packed format. uint, long, float. public unsafe class PixelAccessor : IDisposable where TColor : IPackedVector where TPacked : struct { /// /// The pointer to the pixel buffer. /// private IntPtr dataPointer; /// /// The position of the first pixel in the bitmap. /// private byte* pixelsBase; /// /// Provides a way to access the pixels from unmanaged memory. /// private GCHandle pixelsHandle; /// /// A value indicating whether this instance of the given entity has been disposed. /// /// if this instance has been disposed; otherwise, . /// /// If the entity is disposed, it must not be disposed a second time. The isDisposed field is set the first time the entity /// is disposed. If the isDisposed field is true, then the Dispose() method will not dispose again. This help not to prolong the entity's /// life in the Garbage Collector. /// private bool isDisposed; /// /// Initializes a new instance of the class. /// /// The image to provide pixel access for. public PixelAccessor(ImageBase image) { Guard.NotNull(image, nameof(image)); Guard.MustBeGreaterThan(image.Width, 0, "image width"); Guard.MustBeGreaterThan(image.Height, 0, "image height"); this.Width = image.Width; this.Height = image.Height; this.pixelsHandle = GCHandle.Alloc(image.Pixels, GCHandleType.Pinned); this.dataPointer = this.pixelsHandle.AddrOfPinnedObject(); this.pixelsBase = (byte*)this.dataPointer.ToPointer(); this.PixelSize = Unsafe.SizeOf(); this.RowStride = this.Width * this.PixelSize; } /// /// Finalizes an instance of the class. /// ~PixelAccessor() { this.Dispose(); } /// /// Gets the pointer to the pixel buffer. /// public IntPtr DataPointer => this.dataPointer; /// /// Gets the width of one row in the number of bytes. /// public int PixelSize { get; } /// /// Gets the width of one row in the number of bytes. /// public int RowStride { get; } /// /// Gets the width of the image. /// public int Width { get; } /// /// Gets the height of the image. /// public int Height { get; } /// /// Gets or sets the pixel at the specified position. /// /// The x-coordinate of the pixel. Must be greater than zero and smaller than the width of the pixel. /// The y-coordinate of the pixel. Must be greater than zero and smaller than the width of the pixel. /// The at the specified position. public TColor this[int x, int y] { get { return Unsafe.Read(this.pixelsBase + (y * this.Width + x) * Unsafe.SizeOf()); } set { Unsafe.Write(this.pixelsBase + (y * this.Width + x) * Unsafe.SizeOf(), value); } } /// /// Copies an entire row of pixels. /// /// The x-coordinate of the source row. /// The y-coordinate of the source row. /// The target pixel buffer accessor. /// The x-coordinate of the target row. /// The y-coordinate of the target row. /// The number of pixels to copy public void CopyRow(int sourceX, int sourceY, PixelAccessor target, int targetX, int targetY, int pixelCount) { int size = Unsafe.SizeOf(); byte* sourcePtr = this.pixelsBase + (sourceY * this.Width + sourceX) * size; byte* targetPtr = target.pixelsBase + (targetY * target.Width + targetX) * size; uint byteCount = (uint)(pixelCount * size); Unsafe.CopyBlock(targetPtr, sourcePtr, byteCount); } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { if (this.isDisposed) { return; } if (this.pixelsHandle.IsAllocated) { this.pixelsHandle.Free(); } this.dataPointer = IntPtr.Zero; this.pixelsBase = null; // Note disposing is done. this.isDisposed = true; // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SuppressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); } } }