diff --git a/src/ImageProcessorCore/Image/ImageBase.cs b/src/ImageProcessorCore/Image/ImageBase.cs
index 4d17d9f01..d6333de10 100644
--- a/src/ImageProcessorCore/Image/ImageBase.cs
+++ b/src/ImageProcessorCore/Image/ImageBase.cs
@@ -3,6 +3,7 @@
// Licensed under the Apache License, Version 2.0.
//
+
namespace ImageProcessorCore
{
using System;
@@ -15,10 +16,15 @@ namespace ImageProcessorCore
/// The pixel format.
/// The packed format. uint, long, float.
[DebuggerDisplay("Image: {Width}x{Height}")]
- public abstract class ImageBase : IImageBase
+ public abstract unsafe class ImageBase : IImageBase
where TColor : IPackedVector
where TPacked : struct
{
+ ///
+ /// The image pixels
+ ///
+ private TColor[] pixelBuffer;
+
///
/// Initializes a new instance of the class.
///
@@ -41,7 +47,7 @@ namespace ImageProcessorCore
this.Width = width;
this.Height = height;
- this.Pixels = new TColor[width * height];
+ this.pixelBuffer = new TColor[width * height];
}
///
@@ -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 sourcePixels = other.Lock())
+ using (PixelAccessor target = this.Lock())
+ {
+ sourcePixels.CopyImage(target);
+ }
}
///
@@ -73,7 +83,8 @@ namespace ImageProcessorCore
public int MaxHeight { get; set; } = int.MaxValue;
///
- public TColor[] Pixels { get; private set; }
+ //public TColor[] Pixels { get; private set; }
+ public TColor[] Pixels => this.pixelBuffer;
///
public int Width { get; private set; }
@@ -106,7 +117,7 @@ namespace ImageProcessorCore
this.Width = width;
this.Height = height;
- this.Pixels = pixels;
+ this.pixelBuffer = pixels;
}
///
@@ -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);
}
///
diff --git a/src/ImageProcessorCore/Image/PixelAccessor.cs b/src/ImageProcessorCore/Image/PixelAccessor.cs
index 8ebfb355e..7561150a5 100644
--- a/src/ImageProcessorCore/Image/PixelAccessor.cs
+++ b/src/ImageProcessorCore/Image/PixelAccessor.cs
@@ -77,7 +77,7 @@ namespace ImageProcessorCore
public IntPtr DataPointer => this.dataPointer;
///
- /// Gets the width of one row in the number of bytes.
+ /// Gets the size of a single pixel in the number of bytes.
///
public int PixelSize { get; }
@@ -106,19 +106,18 @@ namespace ImageProcessorCore
{
get { return Unsafe.Read(this.pixelsBase + (y * this.Width + x) * Unsafe.SizeOf()); }
set { Unsafe.Write(this.pixelsBase + (y * this.Width + x) * Unsafe.SizeOf(), value); }
-
}
///
- /// Copies an entire row of pixels.
+ /// Copies a block of pixels at the specified position.
///
- /// The x-coordinate of the source row.
- /// The y-coordinate of the source row.
+ /// The x-coordinate of the source image.
+ /// The y-coordinate of the source image.
/// The target pixel buffer accessor.
- /// The x-coordinate of the target row.
- /// The y-coordinate of the target row.
+ /// The x-coordinate of the target image.
+ /// The y-coordinate of the target image.
/// The number of pixels to copy
- public void CopyRow(int sourceX, int sourceY, PixelAccessor target, int targetX, int targetY, int pixelCount)
+ public void CopyBlock(int sourceX, int sourceY, PixelAccessor target, int targetX, int targetY, int pixelCount)
{
int size = Unsafe.SizeOf();
byte* sourcePtr = this.pixelsBase + (sourceY * this.Width + sourceX) * size;
@@ -128,6 +127,15 @@ namespace ImageProcessorCore
Unsafe.CopyBlock(targetPtr, sourcePtr, byteCount);
}
+ ///
+ /// Copies an entire image.
+ ///
+ /// The target pixel buffer accessor.
+ public void CopyImage(PixelAccessor target)
+ {
+ this.CopyBlock(0, 0, target, 0, 0, target.Width * target.Height);
+ }
+
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
diff --git a/tests/ImageProcessorCore.Benchmarks/Image/CopyPixels.cs b/tests/ImageProcessorCore.Benchmarks/Image/CopyPixels.cs
index df0706bc6..3e426f747 100644
--- a/tests/ImageProcessorCore.Benchmarks/Image/CopyPixels.cs
+++ b/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];