From aa11973f2d8978260e321fa310b5153cf7527342 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 6 Jul 2016 20:57:35 +1000 Subject: [PATCH] ImageRgba32 Former-commit-id: e8d174508130e99cb9152e3c6dad690232425075 Former-commit-id: 4191408f0e2678dfb6937918c46a0d588da073d7 Former-commit-id: 3dc34dfac9b7e02f3dca4e80b1d8cf41fe40ee35 --- GenericImage/ImageRgba32.cs | 25 +++++ GenericImage/PackedVectors/Rgba64.cs | 8 +- GenericImage/PixelAccessorRgba32.cs | 148 +++++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 GenericImage/ImageRgba32.cs create mode 100644 GenericImage/PixelAccessorRgba32.cs diff --git a/GenericImage/ImageRgba32.cs b/GenericImage/ImageRgba32.cs new file mode 100644 index 000000000..8ec301c2e --- /dev/null +++ b/GenericImage/ImageRgba32.cs @@ -0,0 +1,25 @@ +namespace GenericImage +{ + using GenericImage.PackedVectors; + + public class ImageRgba32 : IImageBase + { + public ImageRgba32(int width, int height) + { + this.Width = width; + this.Height = height; + this.Pixels = new Rgba32[width * height]; + } + + public Rgba32[] Pixels { get; } + + public int Width { get; } + + public int Height { get; } + + public IPixelAccessor Lock() + { + return new PixelAccessorRgba32(this); + } + } +} diff --git a/GenericImage/PackedVectors/Rgba64.cs b/GenericImage/PackedVectors/Rgba64.cs index 06821f63e..53b01d1c3 100644 --- a/GenericImage/PackedVectors/Rgba64.cs +++ b/GenericImage/PackedVectors/Rgba64.cs @@ -84,9 +84,9 @@ public Vector4 ToVector4() { return new Vector4( - this.PackedValue & 0xFFFF, - (this.PackedValue >> 16) & 0xFFFF, (this.PackedValue >> 32) & 0xFFFF, + (this.PackedValue >> 16) & 0xFFFF, + this.PackedValue & 0xFFFF, (this.PackedValue >> 48) & 0xFFFF) / 65535f; } @@ -140,9 +140,9 @@ /// private static ulong Pack(ref Vector4 vector) { - return (ulong)Math.Round(vector.X) | + return ((ulong)Math.Round(vector.Z) << 32) | ((ulong)Math.Round(vector.Y) << 16) | - ((ulong)Math.Round(vector.Z) << 32) | + (ulong)Math.Round(vector.X) | ((ulong)Math.Round(vector.W) << 48); } diff --git a/GenericImage/PixelAccessorRgba32.cs b/GenericImage/PixelAccessorRgba32.cs new file mode 100644 index 000000000..3af32aae2 --- /dev/null +++ b/GenericImage/PixelAccessorRgba32.cs @@ -0,0 +1,148 @@ +namespace GenericImage +{ + using System; + using System.Runtime.InteropServices; + + using GenericImage.PackedVectors; + + /// + /// Provides per-pixel access to an images pixels. + /// + public sealed unsafe class PixelAccessorRgba32 : IPixelAccessor + { + /// + /// The position of the first pixel in the bitmap. + /// + private Rgba32* 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 PixelAccessorRgba32(IImageBase 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.pixelsBase = (Rgba32*)this.pixelsHandle.AddrOfPinnedObject().ToPointer(); + } + + /// + /// Finalizes an instance of the class. + /// + ~PixelAccessorRgba32() + { + this.Dispose(); + } + + /// + /// Gets the width of the image. + /// + public int Width { get; } + + /// + /// Gets the height of the image. + /// + public int Height { get; } + + /// + /// Gets or sets the color of a 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 IPackedVector this[int x, int y] + { + get + { +#if DEBUG + if ((x < 0) || (x >= this.Width)) + { + throw new ArgumentOutOfRangeException(nameof(x), "Value cannot be less than zero or greater than the bitmap width."); + } + + if ((y < 0) || (y >= this.Height)) + { + throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height."); + } +#endif + return *(this.pixelsBase + ((y * this.Width) + x)); + } + + set + { +#if DEBUG + if ((x < 0) || (x >= this.Width)) + { + throw new ArgumentOutOfRangeException(nameof(x), "Value cannot be less than zero or greater than the bitmap width."); + } + + if ((y < 0) || (y >= this.Height)) + { + throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height."); + } +#endif + *(this.pixelsBase + ((y * this.Width) + x)) = (Rgba32)value; + } + } + + /// + /// 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.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); + } + } +}