Browse Source

Clean up PixelRow

pull/20/head
James Jackson-South 10 years ago
parent
commit
b5c4256b93
  1. 2
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  2. 4
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  3. 18
      src/ImageSharp/Image/PixelAccessor.cs
  4. 158
      src/ImageSharp/Image/PixelRow.cs
  5. 8
      src/ImageSharp/PixelAccessor.cs

2
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);

4
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);
}
}
}

18
src/ImageSharp/Image/PixelAccessor.cs

@ -24,7 +24,7 @@ namespace ImageSharp
private IntPtr dataPointer;
/// <summary>
/// The position of the first pixel in the bitmap.
/// The position of the first pixel in the image.
/// </summary>
private byte* pixelsBase;
@ -231,7 +231,7 @@ namespace ImageSharp
/// <param name="width">The width.</param>
protected virtual void CopyFromZYX(PixelRow<TColor, TPacked> 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
/// <param name="width">The width.</param>
protected virtual void CopyFromZYXW(PixelRow<TColor, TPacked> 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
/// <param name="width">The width.</param>
protected virtual void CopyFromXYZ(PixelRow<TColor, TPacked> 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
/// <param name="width">The width.</param>
protected virtual void CopyFromXYZW(PixelRow<TColor, TPacked> 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;
}
}

158
src/ImageSharp/Image/PixelRow.cs

@ -9,77 +9,171 @@ namespace ImageSharp
using System.IO;
using System.Runtime.InteropServices;
public unsafe sealed class PixelRow<TColor, TPacked> : IDisposable
/// <summary>
/// Represents a row of generic <see cref="Image{TColor,TPacked}"/> pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
public sealed unsafe class PixelRow<TColor, TPacked> : IDisposable
where TColor : struct, IPackedPixel<TPacked>
where TPacked : struct
{
private readonly GCHandle handle;
/// <summary>
/// Provides a way to access the pixels from unmanaged memory.
/// </summary>
private readonly GCHandle pixelsHandle;
/// <summary>
/// The pointer to the pixel buffer.
/// </summary>
private IntPtr dataPointer;
/// <summary>
/// A value indicating whether this instance of the given entity has been disposed.
/// </summary>
/// <value><see langword="true"/> if this instance has been disposed; otherwise, <see langword="false"/>.</value>
/// <remarks>
/// 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.
/// </remarks>
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="PixelRow{TColor,TPacked}"/> class.
/// </summary>
/// <param name="width">The width. </param>
/// <param name="componentOrder">The component order.</param>
public PixelRow(int width, ComponentOrder componentOrder)
: this(width, componentOrder, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelRow{TColor,TPacked}"/> class.
/// </summary>
/// <param name="width">The width. </param>
/// <param name="componentOrder">The component order.</param>
/// <param name="padding">The number of bytes to pad each row.</param>
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();
}
/// <summary>
/// Finalizes an instance of the <see cref="PixelRow{TColor,TPacked}"/> class.
/// </summary>
~PixelRow()
{
this.Dispose();
}
public byte[] Data { get; }
/// <summary>
/// Gets the data in bytes.
/// </summary>
public byte[] Bytes { get; }
/// <summary>
/// Gets the pointer to the pixel buffer.
/// </summary>
public IntPtr DataPointer => this.dataPointer;
public byte* DataPointer { get; private set; }
/// <summary>
/// Gets the data pointer.
/// </summary>
public byte* PixelBase { get; private set; }
/// <summary>
/// Gets the component order.
/// </summary>
public ComponentOrder ComponentOrder { get; }
/// <summary>
/// Gets the width.
/// </summary>
public int Width { get; }
/// <summary>
/// Reads the stream to the row.
/// </summary>
/// <param name="stream">The stream.</param>
public void Read(Stream stream)
{
stream.Read(this.Data, 0, this.Data.Length);
stream.Read(this.Bytes, 0, this.Bytes.Length);
}
/// <summary>
/// Writes the row to the stream.
/// </summary>
/// <param name="stream">The stream.</param>
public void Write(Stream stream)
{
stream.Write(this.Data, 0, this.Data.Length);
stream.Write(this.Bytes, 0, this.Bytes.Length);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
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);
}
/// <summary>
/// Gets component count for the given order.
/// </summary>
/// <param name="componentOrder">The component order.</param>
/// <returns>
/// The <see cref="int"/>.
/// </returns>
/// <exception cref="NotSupportedException">
/// Thrown if an invalid order is given.
/// </exception>
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();
}
}
}

8
src/ImageSharp/PixelAccessor.cs

@ -25,7 +25,7 @@ namespace ImageSharp
/// <inheritdoc />
protected override void CopyFromZYX(PixelRow<Color, uint> 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
/// <inheritdoc />
protected override void CopyFromZYXW(PixelRow<Color, uint> 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<Color, uint> 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<Color, uint> 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++)
{

Loading…
Cancel
Save