@ -44,6 +44,11 @@ namespace ImageSharp
/// </remarks>
private bool isDisposed ;
/// <summary>
/// The pixels data
/// </summary>
private TColor [ ] pixels ;
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}"/> class.
/// </summary>
@ -54,13 +59,7 @@ namespace ImageSharp
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 < TColor > ( ) ;
this . RowStride = this . Width * this . PixelSize ;
this . SetPixelBufferUnsafe ( image . Width , image . Height , image . Pixels , false ) ;
this . ParallelOptions = image . Configuration . ParallelOptions ;
}
@ -71,6 +70,28 @@ namespace ImageSharp
/// <param name="height">The height of the image represented by the pixel buffer.</param>
/// <param name="pixels">The pixel buffer.</param>
public PixelAccessor ( int width , int height , TColor [ ] pixels )
: this ( width , height , pixels , false )
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}"/> class.
/// </summary>
/// <param name="width">Gets the width of the image represented by the pixel buffer.</param>
/// <param name="height">The height of the image represented by the pixel buffer.</param>
public PixelAccessor ( int width , int height )
: this ( width , height , PixelPool < TColor > . RentPixels ( width * height ) , true )
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}" /> class.
/// </summary>
/// <param name="width">Gets the width of the image represented by the pixel buffer.</param>
/// <param name="height">The height of the image represented by the pixel buffer.</param>
/// <param name="pixels">The pixel buffer.</param>
/// <param name="pooledMemory">if set to <c>true</c> then the TColor[] is from the PixelPool{TColor} thus should be returned once disposed.</param>
private PixelAccessor ( int width , int height , TColor [ ] pixels , bool pooledMemory )
{
Guard . NotNull ( pixels , nameof ( pixels ) ) ;
Guard . MustBeGreaterThan ( width , 0 , nameof ( width ) ) ;
@ -81,13 +102,8 @@ namespace ImageSharp
throw new ArgumentException ( $"Pixel array must have the length of at least {width * height}." ) ;
}
this . Width = width ;
this . Height = height ;
this . pixelsHandle = GCHandle . Alloc ( pixels , GCHandleType . Pinned ) ;
this . dataPointer = this . pixelsHandle . AddrOfPinnedObject ( ) ;
this . pixelsBase = ( byte * ) this . dataPointer . ToPointer ( ) ;
this . PixelSize = Unsafe . SizeOf < TColor > ( ) ;
this . RowStride = this . Width * this . PixelSize ;
this . SetPixelBufferUnsafe ( width , height , pixels , pooledMemory ) ;
this . ParallelOptions = Configuration . Default . ParallelOptions ;
}
@ -99,6 +115,14 @@ namespace ImageSharp
this . Dispose ( ) ;
}
/// <summary>
/// Gets a value indicating whether [pooled memory].
/// </summary>
/// <value>
/// <c>true</c> if [pooled memory]; otherwise, <c>false</c>.
/// </value>
public bool PooledMemory { get ; private set ; }
/// <summary>
/// Gets the pointer to the pixel buffer.
/// </summary>
@ -107,22 +131,22 @@ namespace ImageSharp
/// <summary>
/// Gets the size of a single pixel in the number of bytes.
/// </summary>
public int PixelSize { get ; }
public int PixelSize { get ; private set ; }
/// <summary>
/// Gets the width of one row in the number of bytes.
/// </summary>
public int RowStride { get ; }
public int RowStride { get ; private set ; }
/// <summary>
/// Gets the width of the image.
/// </summary>
public int Width { get ; }
public int Width { get ; private set ; }
/// <summary>
/// Gets the height of the image.
/// </summary>
public int Height { get ; }
public int Height { get ; private set ; }
/// <summary>
/// Gets the global parallel options for processing tasks in parallel.
@ -221,13 +245,7 @@ namespace ImageSharp
return ;
}
if ( this . pixelsHandle . IsAllocated )
{
this . pixelsHandle . Free ( ) ;
}
this . dataPointer = IntPtr . Zero ;
this . pixelsBase = null ;
this . UnPinPixels ( ) ;
// Note disposing is done.
this . isDisposed = true ;
@ -238,6 +256,12 @@ namespace ImageSharp
// and prevent finalization code for this object
// from executing a second time.
GC . SuppressFinalize ( this ) ;
if ( this . PooledMemory )
{
PixelPool < TColor > . ReturnPixels ( this . pixels ) ;
this . pixels = null ;
}
}
/// <summary>
@ -248,6 +272,22 @@ namespace ImageSharp
Unsafe . InitBlock ( this . pixelsBase , 0 , ( uint ) ( this . RowStride * this . Height ) ) ;
}
/// <summary>
/// Sets the pixel buffer in an unsafe manor this should not be used unless you know what its doing!!!
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="pixels">The pixels.</param>
/// <param name="pooledMemory">if set to <c>true</c> [pooled memory].</param>
/// <returns>Returns the old pixel data thats has gust been replaced.</returns>
/// <remarks>If PixelAccessor.PooledMemory is true then caller is responsible for ensuring PixelPool.ReturnPixels() is called.</remarks>
internal TColor [ ] ReturnCurrentPixelsAndReplaceThemInternally ( int width , int height , TColor [ ] pixels , bool pooledMemory )
{
TColor [ ] oldPixels = this . pixels ;
this . SetPixelBufferUnsafe ( width , height , pixels , pooledMemory ) ;
return oldPixels ;
}
/// <summary>
/// Copies the pixels to another <see cref="PixelAccessor{TColor}"/> of the same size.
/// </summary>
@ -472,6 +512,54 @@ namespace ImageSharp
return this . pixelsBase + ( ( ( y * this . Width ) + x ) * Unsafe . SizeOf < TColor > ( ) ) ;
}
/// <summary>
/// Sets the pixel buffer in an unsafe manor this should not be used unless you know what its doing!!!
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="pixels">The pixels.</param>
/// <param name="pooledMemory">if set to <c>true</c> [pooled memory].</param>
private void SetPixelBufferUnsafe ( int width , int height , TColor [ ] pixels , bool pooledMemory )
{
this . pixels = pixels ;
this . PooledMemory = pooledMemory ;
this . Width = width ;
this . Height = height ;
this . PinPixels ( ) ;
this . PixelSize = Unsafe . SizeOf < TColor > ( ) ;
this . RowStride = this . Width * this . PixelSize ;
}
/// <summary>
/// Pins the pixels data.
/// </summary>
private void PinPixels ( )
{
// unpin any old pixels just incase
this . UnPinPixels ( ) ;
this . pixelsHandle = GCHandle . Alloc ( this . pixels , GCHandleType . Pinned ) ;
this . dataPointer = this . pixelsHandle . AddrOfPinnedObject ( ) ;
this . pixelsBase = ( byte * ) this . dataPointer . ToPointer ( ) ;
}
/// <summary>
/// Unpins pixels data.
/// </summary>
private void UnPinPixels ( )
{
if ( this . pixelsBase ! = null )
{
if ( this . pixelsHandle . IsAllocated )
{
this . pixelsHandle . Free ( ) ;
}
this . dataPointer = IntPtr . Zero ;
this . pixelsBase = null ;
}
}
/// <summary>
/// Copy an area of pixels to the image.
/// </summary>