Browse Source

Faster image copy.

Former-commit-id: 9d5d3ae4df90d8cd7d589fe02aa08c9d2e3f34e2
Former-commit-id: 148a1fea5caff3840c7b8f3e84a1dcff48c6928d
Former-commit-id: 3b8d0e35227541406142fd6829e1bdeddd771c4e
af/merge-core
James Jackson-South 10 years ago
parent
commit
bc491b12d2
  1. 31
      src/ImageProcessorCore/Image/ImageBase.cs
  2. 24
      src/ImageProcessorCore/Image/PixelAccessor.cs
  3. 2
      tests/ImageProcessorCore.Benchmarks/Image/CopyPixels.cs

31
src/ImageProcessorCore/Image/ImageBase.cs

@ -3,6 +3,7 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
using System;
@ -15,10 +16,15 @@ namespace ImageProcessorCore
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
[DebuggerDisplay("Image: {Width}x{Height}")]
public abstract class ImageBase<TColor, TPacked> : IImageBase<TColor, TPacked>
public abstract unsafe class ImageBase<TColor, TPacked> : IImageBase<TColor, TPacked>
where TColor : IPackedVector<TPacked>
where TPacked : struct
{
/// <summary>
/// The image pixels
/// </summary>
private TColor[] pixelBuffer;
/// <summary>
/// Initializes a new instance of the <see cref="ImageBase{TColor, TPacked}"/> class.
/// </summary>
@ -41,7 +47,7 @@ namespace ImageProcessorCore
this.Width = width;
this.Height = height;
this.Pixels = new TColor[width * height];
this.pixelBuffer = new TColor[width * height];
}
/// <summary>
@ -61,9 +67,13 @@ namespace ImageProcessorCore
this.Height = other.Height;
this.CopyProperties(other);
// Copy the pixels. Don't use Unsafe.Copy as it is breaking edge detection.
this.Pixels = new TColor[this.Width * this.Height];
Array.Copy(other.Pixels, this.Pixels, other.Pixels.Length);
// Copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here.
this.pixelBuffer = new TColor[this.Width * this.Height];
using (PixelAccessor<TColor, TPacked> sourcePixels = other.Lock())
using (PixelAccessor<TColor, TPacked> target = this.Lock())
{
sourcePixels.CopyImage(target);
}
}
/// <inheritdoc/>
@ -73,7 +83,8 @@ namespace ImageProcessorCore
public int MaxHeight { get; set; } = int.MaxValue;
/// <inheritdoc/>
public TColor[] Pixels { get; private set; }
//public TColor[] Pixels { get; private set; }
public TColor[] Pixels => this.pixelBuffer;
/// <inheritdoc/>
public int Width { get; private set; }
@ -106,7 +117,7 @@ namespace ImageProcessorCore
this.Width = width;
this.Height = height;
this.Pixels = pixels;
this.pixelBuffer = pixels;
}
/// <inheritdoc/>
@ -123,9 +134,9 @@ namespace ImageProcessorCore
this.Width = width;
this.Height = height;
// Copy the pixels. Don't use Unsafe.Copy as it is breaking edge detection.
this.Pixels = new TColor[pixels.Length];
Array.Copy(pixels, this.Pixels, pixels.Length);
// Copy the pixels. TODO: use Unsafe.Copy.
this.pixelBuffer = new TColor[pixels.Length];
Array.Copy(pixels, this.pixelBuffer, pixels.Length);
}
/// <inheritdoc/>

24
src/ImageProcessorCore/Image/PixelAccessor.cs

@ -77,7 +77,7 @@ namespace ImageProcessorCore
public IntPtr DataPointer => this.dataPointer;
/// <summary>
/// Gets the width of one row in the number of bytes.
/// Gets the size of a single pixel in the number of bytes.
/// </summary>
public int PixelSize { get; }
@ -106,19 +106,18 @@ namespace ImageProcessorCore
{
get { return Unsafe.Read<TColor>(this.pixelsBase + (y * this.Width + x) * Unsafe.SizeOf<TColor>()); }
set { Unsafe.Write(this.pixelsBase + (y * this.Width + x) * Unsafe.SizeOf<TColor>(), value); }
}
/// <summary>
/// Copies an entire row of pixels.
/// Copies a block of pixels at the specified position.
/// </summary>
/// <param name="sourceX">The x-coordinate of the source row.</param>
/// <param name="sourceY">The y-coordinate of the source row.</param>
/// <param name="sourceX">The x-coordinate of the source image.</param>
/// <param name="sourceY">The y-coordinate of the source image.</param>
/// <param name="target">The target pixel buffer accessor.</param>
/// <param name="targetX">The x-coordinate of the target row.</param>
/// <param name="targetY">The y-coordinate of the target row.</param>
/// <param name="targetX">The x-coordinate of the target image.</param>
/// <param name="targetY">The y-coordinate of the target image.</param>
/// <param name="pixelCount">The number of pixels to copy</param>
public void CopyRow(int sourceX, int sourceY, PixelAccessor<TColor, TPacked> target, int targetX, int targetY, int pixelCount)
public void CopyBlock(int sourceX, int sourceY, PixelAccessor<TColor, TPacked> target, int targetX, int targetY, int pixelCount)
{
int size = Unsafe.SizeOf<TColor>();
byte* sourcePtr = this.pixelsBase + (sourceY * this.Width + sourceX) * size;
@ -128,6 +127,15 @@ namespace ImageProcessorCore
Unsafe.CopyBlock(targetPtr, sourcePtr, byteCount);
}
/// <summary>
/// Copies an entire image.
/// </summary>
/// <param name="target">The target pixel buffer accessor.</param>
public void CopyImage(PixelAccessor<TColor, TPacked> target)
{
this.CopyBlock(0, 0, target, 0, 0, target.Width * target.Height);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>

2
tests/ImageProcessorCore.Benchmarks/Image/CopyPixels.cs

@ -47,7 +47,7 @@
Bootstrapper.Instance.ParallelOptions,
y =>
{
sourcePixels.CopyRow(0, y, targetPixels, 0, y, source.Width);
sourcePixels.CopyBlock(0, y, targetPixels, 0, y, source.Width);
});
return targetPixels[0, 0];

Loading…
Cancel
Save