|
|
|
@ -2,10 +2,10 @@ |
|
|
|
// Copyright (c) James Jackson-South and contributors.
|
|
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
// </copyright>
|
|
|
|
|
|
|
|
namespace ImageSharp |
|
|
|
{ |
|
|
|
using System; |
|
|
|
using System.Buffers; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.IO; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
|
@ -39,6 +39,11 @@ namespace ImageSharp |
|
|
|
/// </remarks>
|
|
|
|
private bool isDisposed; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// True if <see cref="Bytes"/> was allocated by the constructor (rented from <see cref="BytesPool"/>)
|
|
|
|
/// </summary>
|
|
|
|
private bool isBufferOwner; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class.
|
|
|
|
/// </summary>
|
|
|
|
@ -96,7 +101,7 @@ namespace ImageSharp |
|
|
|
/// <param name="width">The width.</param>
|
|
|
|
/// <param name="componentOrder">The component order.</param>
|
|
|
|
public PixelArea(int width, ComponentOrder componentOrder) |
|
|
|
: this(width, 1, componentOrder, 0) |
|
|
|
: this(width, 1, componentOrder, 0) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
@ -107,7 +112,7 @@ namespace ImageSharp |
|
|
|
/// <param name="componentOrder">The component order.</param>
|
|
|
|
/// <param name="padding">The number of bytes to pad each row.</param>
|
|
|
|
public PixelArea(int width, ComponentOrder componentOrder, int padding) |
|
|
|
: this(width, 1, componentOrder, padding) |
|
|
|
: this(width, 1, componentOrder, padding) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
@ -124,7 +129,8 @@ namespace ImageSharp |
|
|
|
this.Height = height; |
|
|
|
this.ComponentOrder = componentOrder; |
|
|
|
this.RowByteCount = (width * GetComponentCount(componentOrder)) + padding; |
|
|
|
this.Bytes = new byte[this.RowByteCount * height]; |
|
|
|
this.Bytes = BytesPool.Rent(this.RowByteCount * height); |
|
|
|
this.isBufferOwner = true; |
|
|
|
this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned); |
|
|
|
|
|
|
|
// TODO: Why is Resharper warning us about an impure method call?
|
|
|
|
@ -137,7 +143,7 @@ namespace ImageSharp |
|
|
|
/// </summary>
|
|
|
|
~PixelArea() |
|
|
|
{ |
|
|
|
this.Dispose(); |
|
|
|
this.Dispose(false); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -145,20 +151,30 @@ namespace ImageSharp |
|
|
|
/// </summary>
|
|
|
|
public byte[] Bytes { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the component order.
|
|
|
|
/// </summary>
|
|
|
|
public ComponentOrder ComponentOrder { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the pointer to the pixel buffer.
|
|
|
|
/// </summary>
|
|
|
|
public IntPtr DataPointer => this.dataPointer; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the height.
|
|
|
|
/// </summary>
|
|
|
|
public int Height { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the data pointer.
|
|
|
|
/// </summary>
|
|
|
|
public byte* PixelBase { get; private set; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the component order.
|
|
|
|
/// Gets number of bytes in a row.
|
|
|
|
/// </summary>
|
|
|
|
public ComponentOrder ComponentOrder { get; } |
|
|
|
public int RowByteCount { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the width.
|
|
|
|
@ -166,14 +182,17 @@ namespace ImageSharp |
|
|
|
public int Width { get; } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the height.
|
|
|
|
/// Gets the pool used to rent <see cref="Bytes"/>, when it's not coming from an external source
|
|
|
|
/// </summary>
|
|
|
|
public int Height { get; } |
|
|
|
private static ArrayPool<byte> BytesPool => ArrayPool<byte>.Shared; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets number of bytes in a row.
|
|
|
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
|
|
/// </summary>
|
|
|
|
public int RowByteCount { get; } |
|
|
|
public void Dispose() |
|
|
|
{ |
|
|
|
this.Dispose(true); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Reads the stream to the area.
|
|
|
|
@ -193,39 +212,6 @@ namespace ImageSharp |
|
|
|
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.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>
|
|
|
|
/// Resets the bytes of the array to it's initial value.
|
|
|
|
/// </summary>
|
|
|
|
@ -265,8 +251,45 @@ namespace ImageSharp |
|
|
|
int requiredLength = (width * GetComponentCount(componentOrder)) * height; |
|
|
|
if (bytes.Length != requiredLength) |
|
|
|
{ |
|
|
|
throw new ArgumentOutOfRangeException(nameof(bytes), $"Invalid byte array length. Length {bytes.Length}; Should be {requiredLength}."); |
|
|
|
throw new ArgumentOutOfRangeException( |
|
|
|
nameof(bytes), |
|
|
|
$"Invalid byte array length. Length {bytes.Length}; Should be {requiredLength}."); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void Dispose(bool disposing) |
|
|
|
{ |
|
|
|
if (this.isDisposed) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.PixelBase == null) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (this.pixelsHandle.IsAllocated) |
|
|
|
{ |
|
|
|
this.pixelsHandle.Free(); |
|
|
|
} |
|
|
|
|
|
|
|
if (disposing && this.isBufferOwner) |
|
|
|
{ |
|
|
|
BytesPool.Return(this.Bytes); |
|
|
|
} |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |