diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 6c390fa84b..7c3e842aa7 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -292,7 +292,7 @@ namespace ImageSharp.Formats
int offset = 0;
for (int x = 0; x < width; x++)
{
- short temp = BitConverter.ToInt16(row.Data, offset);
+ short temp = BitConverter.ToInt16(row.Bytes, offset);
byte r = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR);
byte g = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG);
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index 8dab460d9d..7c3d18b93f 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -160,7 +160,7 @@ namespace ImageSharp.Formats
for (int y = pixels.Height - 1; y >= 0; y--)
{
pixels.CopyTo(row, y);
- writer.Write(row.Data);
+ writer.Write(row.Bytes);
}
}
}
@@ -181,7 +181,7 @@ namespace ImageSharp.Formats
for (int y = pixels.Height - 1; y >= 0; y--)
{
pixels.CopyTo(row, y);
- writer.Write(row.Data);
+ writer.Write(row.Bytes);
}
}
}
diff --git a/src/ImageSharp/Image/PixelAccessor.cs b/src/ImageSharp/Image/PixelAccessor.cs
index eec9b8cb27..fec50b9720 100644
--- a/src/ImageSharp/Image/PixelAccessor.cs
+++ b/src/ImageSharp/Image/PixelAccessor.cs
@@ -24,7 +24,7 @@ namespace ImageSharp
private IntPtr dataPointer;
///
- /// The position of the first pixel in the bitmap.
+ /// The position of the first pixel in the image.
///
private byte* pixelsBase;
@@ -231,7 +231,7 @@ namespace ImageSharp
/// The width.
protected virtual void CopyFromZYX(PixelRow row, int targetY, int width)
{
- byte* source = row.DataPointer;
+ byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY);
TColor packed = default(TColor);
@@ -255,7 +255,7 @@ namespace ImageSharp
/// The width.
protected virtual void CopyFromZYXW(PixelRow row, int targetY, int width)
{
- byte* source = row.DataPointer;
+ byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY);
TColor packed = default(TColor);
@@ -279,7 +279,7 @@ namespace ImageSharp
/// The width.
protected virtual void CopyFromXYZ(PixelRow row, int targetY, int width)
{
- byte* source = row.DataPointer;
+ byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY);
TColor packed = default(TColor);
@@ -303,7 +303,7 @@ namespace ImageSharp
/// The width.
protected virtual void CopyFromXYZW(PixelRow row, int targetY, int width)
{
- byte* source = row.DataPointer;
+ byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY);
TColor packed = default(TColor);
@@ -330,7 +330,7 @@ namespace ImageSharp
int offset = 0;
for (int x = 0; x < width; x++)
{
- this[x, sourceY].ToBytes(row.Data, offset, ComponentOrder.ZYX);
+ this[x, sourceY].ToBytes(row.Bytes, offset, ComponentOrder.ZYX);
offset += 3;
}
}
@@ -346,7 +346,7 @@ namespace ImageSharp
int offset = 0;
for (int x = 0; x < width; x++)
{
- this[x, sourceY].ToBytes(row.Data, offset, ComponentOrder.ZYXW);
+ this[x, sourceY].ToBytes(row.Bytes, offset, ComponentOrder.ZYXW);
offset += 4;
}
}
@@ -362,7 +362,7 @@ namespace ImageSharp
int offset = 0;
for (int x = 0; x < width; x++)
{
- this[x, sourceY].ToBytes(row.Data, offset, ComponentOrder.XYZ);
+ this[x, sourceY].ToBytes(row.Bytes, offset, ComponentOrder.XYZ);
offset += 3;
}
}
@@ -378,7 +378,7 @@ namespace ImageSharp
int offset = 0;
for (int x = 0; x < width; x++)
{
- this[x, sourceY].ToBytes(row.Data, offset, ComponentOrder.XYZW);
+ this[x, sourceY].ToBytes(row.Bytes, offset, ComponentOrder.XYZW);
offset += 4;
}
}
diff --git a/src/ImageSharp/Image/PixelRow.cs b/src/ImageSharp/Image/PixelRow.cs
index fd5e14d4e5..6ad25dbed0 100644
--- a/src/ImageSharp/Image/PixelRow.cs
+++ b/src/ImageSharp/Image/PixelRow.cs
@@ -9,77 +9,171 @@ namespace ImageSharp
using System.IO;
using System.Runtime.InteropServices;
- public unsafe sealed class PixelRow : IDisposable
+ ///
+ /// Represents a row of generic pixels.
+ ///
+ /// The pixel format.
+ /// The packed format. uint, long, float.
+ public sealed unsafe class PixelRow : IDisposable
where TColor : struct, IPackedPixel
where TPacked : struct
{
- private readonly GCHandle handle;
-
+ ///
+ /// Provides a way to access the pixels from unmanaged memory.
+ ///
+ private readonly GCHandle pixelsHandle;
+
+ ///
+ /// The pointer to the pixel buffer.
+ ///
+ private IntPtr dataPointer;
+
+ ///
+ /// 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 width.
+ /// The component order.
public PixelRow(int width, ComponentOrder componentOrder)
: this(width, componentOrder, 0)
{
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The width.
+ /// The component order.
+ /// The number of bytes to pad each row.
public PixelRow(int width, ComponentOrder componentOrder, int padding)
{
this.Width = width;
this.ComponentOrder = componentOrder;
- this.Data = new byte[(width * GetComponentCount(componentOrder)) + padding];
- this.handle = GCHandle.Alloc(this.Data, GCHandleType.Pinned);
- this.DataPointer = (byte*)this.handle.AddrOfPinnedObject().ToPointer();
+ this.Bytes = new byte[(width * GetComponentCount(componentOrder)) + padding];
+ this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned);
+
+ // TODO: Why is Resharper warning us about an impure method call?
+ this.dataPointer = this.pixelsHandle.AddrOfPinnedObject();
+ this.PixelBase = (byte*)this.dataPointer.ToPointer();
}
+ ///
+ /// Finalizes an instance of the class.
+ ///
~PixelRow()
{
this.Dispose();
}
- public byte[] Data { get; }
+ ///
+ /// Gets the data in bytes.
+ ///
+ public byte[] Bytes { get; }
+
+ ///
+ /// Gets the pointer to the pixel buffer.
+ ///
+ public IntPtr DataPointer => this.dataPointer;
- public byte* DataPointer { get; private set; }
+ ///
+ /// Gets the data pointer.
+ ///
+ public byte* PixelBase { get; private set; }
+ ///
+ /// Gets the component order.
+ ///
public ComponentOrder ComponentOrder { get; }
+ ///
+ /// Gets the width.
+ ///
public int Width { get; }
+ ///
+ /// Reads the stream to the row.
+ ///
+ /// The stream.
public void Read(Stream stream)
{
- stream.Read(this.Data, 0, this.Data.Length);
+ stream.Read(this.Bytes, 0, this.Bytes.Length);
}
+ ///
+ /// Writes the row to the stream.
+ ///
+ /// The stream.
public void Write(Stream stream)
{
- stream.Write(this.Data, 0, this.Data.Length);
+ stream.Write(this.Bytes, 0, this.Bytes.Length);
}
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
public void Dispose()
{
- if (this.DataPointer == null)
- {
- return;
- }
-
- if (this.handle.IsAllocated)
- {
- this.handle.Free();
- }
-
- this.DataPointer = null;
+ if (this.isDisposed)
+ {
+ return;
+ }
+
+ if (this.PixelBase == null)
+ {
+ return;
+ }
+
+ if (this.pixelsHandle.IsAllocated)
+ {
+ this.pixelsHandle.Free();
+ }
+
+ this.dataPointer = IntPtr.Zero;
+ this.PixelBase = null;
+
+ 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);
}
+ ///
+ /// Gets component count for the given order.
+ ///
+ /// The component order.
+ ///
+ /// The .
+ ///
+ ///
+ /// Thrown if an invalid order is given.
+ ///
private static int GetComponentCount(ComponentOrder componentOrder)
{
- switch (componentOrder)
- {
- case ComponentOrder.ZYX:
- case ComponentOrder.XYZ:
- return 3;
- case ComponentOrder.ZYXW:
- case ComponentOrder.XYZW:
- return 4;
- }
-
- throw new NotSupportedException();
+ switch (componentOrder)
+ {
+ case ComponentOrder.ZYX:
+ case ComponentOrder.XYZ:
+ return 3;
+ case ComponentOrder.ZYXW:
+ case ComponentOrder.XYZW:
+ return 4;
+ }
+
+ throw new NotSupportedException();
}
}
}
diff --git a/src/ImageSharp/PixelAccessor.cs b/src/ImageSharp/PixelAccessor.cs
index 88c781832a..ca49255d8c 100644
--- a/src/ImageSharp/PixelAccessor.cs
+++ b/src/ImageSharp/PixelAccessor.cs
@@ -25,7 +25,7 @@ namespace ImageSharp
///
protected override void CopyFromZYX(PixelRow row, int targetY, int width)
{
- byte* source = row.DataPointer;
+ byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY);
for (int x = 0; x < width; x++)
@@ -40,7 +40,7 @@ namespace ImageSharp
///
protected override void CopyFromZYXW(PixelRow row, int targetY, int width)
{
- byte* source = row.DataPointer;
+ byte* source = row.PixelBase;
byte* destination = this.GetRowPointer(targetY);
for (int x = 0; x < width; x++)
@@ -56,7 +56,7 @@ namespace ImageSharp
protected override void CopyToZYX(PixelRow row, int sourceY, int width)
{
byte* source = this.GetRowPointer(sourceY);
- byte* destination = row.DataPointer;
+ byte* destination = row.PixelBase;
for (int x = 0; x < width; x++)
{
@@ -83,7 +83,7 @@ namespace ImageSharp
protected override void CopyToZYXW(PixelRow row, int sourceY, int width)
{
byte* source = this.GetRowPointer(sourceY);
- byte* destination = row.DataPointer;
+ byte* destination = row.PixelBase;
for (int x = 0; x < width; x++)
{