From 36b33a75930ca3cb0aa28c0cdacc598f79a31bf2 Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 21 Sep 2014 00:26:32 +0100 Subject: [PATCH] Switching up fastbitmap class Former-commit-id: 93c59d9d01fe0bcc0751c959ed2f28be4192a500 --- src/ImageProcessor/ImageProcessor.csproj | 5 +- src/ImageProcessor/Imaging/FastBitmap.cs | 96 +++++++++++++++++------- src/ImageProcessorConsole/Program.cs | 3 +- 3 files changed, 76 insertions(+), 28 deletions(-) diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 48106d7c4..0ffb91bf5 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -26,6 +26,7 @@ 4 bin\Debug\ImageProcessor.XML false + true pdbonly @@ -73,7 +74,9 @@ - + + Code + diff --git a/src/ImageProcessor/Imaging/FastBitmap.cs b/src/ImageProcessor/Imaging/FastBitmap.cs index 1ab929c10..97af88356 100644 --- a/src/ImageProcessor/Imaging/FastBitmap.cs +++ b/src/ImageProcessor/Imaging/FastBitmap.cs @@ -13,12 +13,11 @@ namespace ImageProcessor.Imaging using System; using System.Drawing; using System.Drawing.Imaging; - using System.Runtime.InteropServices; /// /// Allows fast access to 's pixel data. /// - public class FastBitmap : IDisposable + public unsafe class FastBitmap : IDisposable { /// /// The bitmap. @@ -36,24 +35,24 @@ namespace ImageProcessor.Imaging private readonly int height; /// - /// The stride width of the bitmap. + /// The number of bytes in a row. /// - private int stride; + private int bytesInARow; /// - /// The bitmap data. + /// The size of the pixel data. /// - private BitmapData bitmapData; + private int pixelDataSize; /// - /// The pixel buffer for holding pixel data. + /// The bitmap data. /// - private byte[] pixelBuffer; + private BitmapData bitmapData; /// - /// The buffer length. + /// The pixel buffer for holding pixel data. /// - private int bufferLength; + private byte* pixelBuffer; /// /// A value indicating whether this instance of the given entity has been disposed. @@ -102,6 +101,23 @@ namespace ImageProcessor.Imaging } } + /// + /// Gets the pixel data for the given position. + /// + /// + /// The x position of the pixel. + /// + /// + /// The y position of the pixel. + /// + /// + /// The . + /// + private PixelData* this[int x, int y] + { + get { return (PixelData*)(this.pixelBuffer + (y * this.bytesInARow) + (x * this.pixelDataSize)); } + } + /// /// Allows the implicit conversion of an instance of to a /// . @@ -150,12 +166,8 @@ namespace ImageProcessor.Imaging throw new ArgumentOutOfRangeException("y", "Value cannot be less than zero or greater than the bitmap height."); } - int position = (x * 4) + (y * this.stride); - byte blue = this.pixelBuffer[position]; - byte green = this.pixelBuffer[position + 1]; - byte red = this.pixelBuffer[position + 2]; - byte alpha = this.pixelBuffer[position + 3]; - return Color.FromArgb(alpha, red, green, blue); + PixelData* data = this[x, y]; + return Color.FromArgb(data->A, data->R, data->G, data->B); } /// @@ -179,11 +191,11 @@ namespace ImageProcessor.Imaging throw new ArgumentOutOfRangeException("y", "Value cannot be less than zero or greater than the bitmap height."); } - int position = (x * 4) + (y * this.stride); - this.pixelBuffer[position] = color.B; - this.pixelBuffer[position + 1] = color.G; - this.pixelBuffer[position + 2] = color.R; - this.pixelBuffer[position + 3] = color.A; + PixelData* data = this[x, y]; + data->R = color.R; + data->G = color.G; + data->B = color.B; + data->A = color.A; } /// @@ -231,14 +243,21 @@ namespace ImageProcessor.Imaging { Rectangle bounds = new Rectangle(Point.Empty, this.bitmap.Size); + // Figure out the number of bytes in a row. This is rounded up to be a multiple + // of 4 bytes, since a scan line in an image must always be a multiple of 4 bytes + // in length. + this.pixelDataSize = sizeof(PixelData); + this.bytesInARow = bounds.Width * this.pixelDataSize; + if (this.bytesInARow % 4 != 0) + { + this.bytesInARow = 4 * ((this.bytesInARow / 4) + 1); + } + // Lock the bitmap this.bitmapData = this.bitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); // Copy the bitmap data across to the array for manipulation. - this.stride = this.bitmapData.Stride; - this.bufferLength = this.stride * this.bitmapData.Height; - this.pixelBuffer = new byte[this.bufferLength]; - Marshal.Copy(this.bitmapData.Scan0, this.pixelBuffer, 0, this.pixelBuffer.Length); + this.pixelBuffer = (byte*)this.bitmapData.Scan0.ToPointer(); } /// @@ -247,10 +266,35 @@ namespace ImageProcessor.Imaging private void UnlockBitmap() { // Copy the RGB values back to the bitmap and unlock the bitmap. - Marshal.Copy(this.pixelBuffer, 0, this.bitmapData.Scan0, this.bufferLength); this.bitmap.UnlockBits(this.bitmapData); this.bitmapData = null; this.pixelBuffer = null; } + + /// + /// The pixel data. + /// + private struct PixelData + { + /// + /// The blue component. + /// + public byte B; + + /// + /// The green component. + /// + public byte G; + + /// + /// The red component. + /// + public byte R; + + /// + /// The alpha component. + /// + public byte A; + } } } diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 4b7651445..73bc58733 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -74,9 +74,10 @@ namespace ImageProcessorConsole //.Resize(new Size((int)(size.Width * 1.1), 0)) //.ContentAwareResize(layer) .Constrain(size) + .Filter(MatrixFilters.Comic) //.Filter(MatrixFilters.HiSatch) //.Pixelate(8) - .GaussianSharpen(10) + //.GaussianSharpen(10) .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); stopwatch.Stop();