Browse Source

Fixing broken FastBitmap bug.

Former-commit-id: 0b89869f0311b368d137202dcaecf28182686c31
Former-commit-id: 3b9bb6480a9853e6b1e4ca2006615942f2205c74
Former-commit-id: e7d59397c0840f8d8293223551958d223f492b68
af/merge-core
James South 11 years ago
parent
commit
bd063d3b6f
  1. 149
      src/ImageProcessor.Playground/Program.cs
  2. 1
      src/ImageProcessor.Playground/images/input/tree.jpg.REMOVED.git-id
  3. 10
      src/ImageProcessor.Web.PostProcessor/PostProcessorBootstrapper.cs
  4. 8
      src/ImageProcessor.Web.PostProcessor/Settings.StyleCop
  5. 9
      src/ImageProcessor/Imaging/Convolution.cs
  6. 130
      src/ImageProcessor/Imaging/FastBitmap.cs
  7. 5
      src/ImageProcessor/Imaging/Filters/Artistic/HalftoneFilter.cs
  8. 4
      src/ImageProcessor/Imaging/Helpers/Adjustments.cs
  9. 1
      src/ImageProcessor/Imaging/Helpers/Effects.cs
  10. 3
      src/ImageProcessor/Settings.StyleCop

149
src/ImageProcessor.Playground/Program.cs

@ -60,7 +60,8 @@ namespace ImageProcessor.PlayGround
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "gamma-1.0-or-2.2.png"));
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "gamma_dalai_lama_gray.jpg"));
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "Arc-de-Triomphe-France.jpg"));
FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "Martin-Schoeller-Jack-Nicholson-Portrait.jpeg"));
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "Martin-Schoeller-Jack-Nicholson-Portrait.jpeg"));
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "tree.jpg"));
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "test2.png"));
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "120430.gif"));
//FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "rickroll.original.gif"));
@ -70,87 +71,89 @@ namespace ImageProcessor.PlayGround
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif");
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".png", ".jpg", ".jpeg");
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".jpg", ".jpeg", ".jfif");
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png");
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".png");
IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png");
//foreach (FileInfo fileInfo in files)
//{
// if (fileInfo.Name == "test5.jpg")
// {
// continue;
// }
foreach (FileInfo fileInfo in files)
{
if (fileInfo.Name == "test5.jpg")
{
continue;
}
byte[] photoBytes = File.ReadAllBytes(fileInfo.FullName);
Console.WriteLine("Processing: " + fileInfo.Name);
byte[] photoBytes = File.ReadAllBytes(fileInfo.FullName);
Console.WriteLine("Processing: " + fileInfo.Name);
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
// ImageProcessor
using (MemoryStream inStream = new MemoryStream(photoBytes))
{
using (ImageFactory imageFactory = new ImageFactory(true, false))
// ImageProcessor
using (MemoryStream inStream = new MemoryStream(photoBytes))
{
Size size = new Size(600, 0);
//CropLayer cropLayer = new CropLayer(20, 20, 20, 20, ImageProcessor.Imaging.CropMode.Percentage);
//ResizeLayer layer = new ResizeLayer(size, ResizeMode.Max, AnchorPosition.Center, false);
//ContentAwareResizeLayer layer = new ContentAwareResizeLayer(size)
//{
// ConvolutionType = ConvolutionType.Sobel
//};
// Load, resize, set the format and quality and save an image.
imageFactory.Load(inStream)
//.DetectObjects(EmbeddedHaarCascades.FrontFaceDefault)
//.Overlay(new ImageLayer
// {
// Image = overlay,
// Opacity = 50
// })
//.Alpha(50)
//.BackgroundColor(Color.White)
//.Resize(new Size((int)(size.Width * 1.1), 0))
//.ContentAwareResize(layer)
//.Constrain(size)
//.Mask(mask)
//.Format(new PngFormat())
//.BackgroundColor(Color.Cyan)
//.ReplaceColor(Color.FromArgb(255, 223, 224), Color.FromArgb(121, 188, 255), 128)
//.GaussianSharpen(3)
//.Saturation(20)
.Resize(size)
//.Resize(new ResizeLayer(size, ResizeMode.Max))
// .Resize(new ResizeLayer(size, ResizeMode.Stretch))
//.DetectEdges(new Laplacian3X3EdgeFilter(), true)
//.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.GaussianBlur(new GaussianLayer(10, 11))
//.EntropyCrop()
//.Halftone()
//.RotateBounded(150, false)
//.Crop(cropLayer)
//.Rotate(140)
//.Filter(MatrixFilters.Invert)
//.Contrast(50)
//.Filter(MatrixFilters.Comic)
//.Flip()
//.Filter(MatrixFilters.HiSatch)
//.Pixelate(8)
//.GaussianSharpen(10)
//.Format(new PngFormat() { IsIndexed = true })
//.Format(new PngFormat() )
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
//.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".png")));
stopwatch.Stop();
using (ImageFactory imageFactory = new ImageFactory(true, true))
{
Size size = new Size(600, 0);
//CropLayer cropLayer = new CropLayer(20, 20, 20, 20, ImageProcessor.Imaging.CropMode.Percentage);
//ResizeLayer layer = new ResizeLayer(size, ResizeMode.Max, AnchorPosition.Center, false);
//ContentAwareResizeLayer layer = new ContentAwareResizeLayer(size)
//{
// ConvolutionType = ConvolutionType.Sobel
//};
// Load, resize, set the format and quality and save an image.
imageFactory.Load(inStream)
//.DetectObjects(EmbeddedHaarCascades.FrontFaceDefault)
//.Overlay(new ImageLayer
// {
// Image = overlay,
// Opacity = 50
// })
//.Alpha(50)
//.BackgroundColor(Color.White)
//.Resize(new Size((int)(size.Width * 1.1), 0))
//.ContentAwareResize(layer)
//.Constrain(size)
//.Mask(mask)
//.Format(new PngFormat())
//.BackgroundColor(Color.Cyan)
//.ReplaceColor(Color.FromArgb(255, 223, 224), Color.FromArgb(121, 188, 255), 128)
//.GaussianSharpen(3)
//.Saturation(20)
//.Resize(size)
//.Resize(new ResizeLayer(size, ResizeMode.Max))
// .Resize(new ResizeLayer(size, ResizeMode.Stretch))
//.DetectEdges(new SobelEdgeFilter(), true)
//.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.GaussianBlur(new GaussianLayer(10, 11))
//.EntropyCrop()
.Halftone()
//.RotateBounded(150, false)
//.Crop(cropLayer)
//.Rotate(140)
//.Filter(MatrixFilters.Invert)
//.Brightness(-5)
//.Contrast(50)
//.Filter(MatrixFilters.Comic)
//.Flip()
//.Filter(MatrixFilters.HiSatch)
//.Pixelate(8)
//.GaussianSharpen(10)
//.Format(new PngFormat() { IsIndexed = true })
//.Format(new PngFormat() )
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
//.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".png")));
stopwatch.Stop();
}
}
}
long peakWorkingSet64 = Process.GetCurrentProcess().PeakWorkingSet64;
float mB = peakWorkingSet64 / (float)1024 / 1024;
long peakWorkingSet64 = Process.GetCurrentProcess().PeakWorkingSet64;
float mB = peakWorkingSet64 / (float)1024 / 1024;
Console.WriteLine(@"Completed {0} in {1:s\.fff} secs {2}Peak memory usage was {3} bytes or {4} Mb.", fileInfo.Name, stopwatch.Elapsed, Environment.NewLine, peakWorkingSet64.ToString("#,#"), mB);
Console.WriteLine(@"Completed {0} in {1:s\.fff} secs {2}Peak memory usage was {3} bytes or {4} Mb.", fileInfo.Name, stopwatch.Elapsed, Environment.NewLine, peakWorkingSet64.ToString("#,#"), mB);
//Console.WriteLine("Processed: " + fileInfo.Name + " in " + stopwatch.ElapsedMilliseconds + "ms");
//}
//Console.WriteLine("Processed: " + fileInfo.Name + " in " + stopwatch.ElapsedMilliseconds + "ms");
}
Console.ReadLine();
}

1
src/ImageProcessor.Playground/images/input/tree.jpg.REMOVED.git-id

@ -0,0 +1 @@
f5e8e6f09d2e518da37e698b6113b82e8f21dcd1

10
src/ImageProcessor.Web.PostProcessor/PostProcessorBootstrapper.cs

@ -58,11 +58,11 @@ namespace ImageProcessor.Web.PostProcessor
// Get the resources and copy them across.
Dictionary<string, string> resources = new Dictionary<string, string>
{
{"gifsicle.exe","ImageProcessor.Web.PostProcessor.Resources.Unmanaged." + folder + ".gifsicle.exe"},
{"jpegtran.exe","ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.jpegtran.exe"},
{"optipng.exe","ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.optipng.exe"},
{"pngout.exe","ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.pngout.exe"},
{"png.cmd","ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.png.cmd" }
{ "gifsicle.exe", "ImageProcessor.Web.PostProcessor.Resources.Unmanaged." + folder + ".gifsicle.exe" },
{ "jpegtran.exe", "ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.jpegtran.exe" },
{ "optipng.exe", "ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.optipng.exe" },
{ "pngout.exe", "ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.pngout.exe" },
{ "png.cmd", "ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.png.cmd" }
};
// Write the files out to the bin folder.

8
src/ImageProcessor.Web.PostProcessor/Settings.StyleCop

@ -1 +1,7 @@
<StyleCopSettings Version="105" />
<StyleCopSettings Version="105">
<GlobalSettings>
<CollectionProperty Name="RecognizedWords">
<Value>executables</Value>
</CollectionProperty>
</GlobalSettings>
</StyleCopSettings>

9
src/ImageProcessor/Imaging/Convolution.cs

@ -335,10 +335,6 @@ namespace ImageProcessor.Imaging
green += k * color.G;
blue += k * color.B;
alpha += k * color.A;
//red += k * (color.R * color.R);
//green += k * (color.G * color.G);
//blue += k * (color.B * color.B);
//alpha += k * (color.A * color.A);
processedKernelSize++;
}
@ -364,11 +360,6 @@ namespace ImageProcessor.Imaging
// Check and apply the divider
if ((long)divider != 0)
{
//red = Math.Sqrt(red / divider);
//green = Math.Sqrt(green / divider);
//blue = Math.Sqrt(blue / divider);
//alpha = Math.Sqrt(alpha / divider);
red /= divider;
green /= divider;
blue /= divider;

130
src/ImageProcessor/Imaging/FastBitmap.cs

@ -22,6 +22,30 @@ namespace ImageProcessor.Imaging
/// </summary>
public unsafe class FastBitmap : IDisposable
{
/// <summary>
/// The integral representation of the 8bppIndexed pixel format.
/// </summary>
// ReSharper disable once InconsistentNaming
private const int Format8bppIndexed = (int)PixelFormat.Format8bppIndexed;
/// <summary>
/// The integral representation of the 24bppRgb pixel format.
/// </summary>
// ReSharper disable once InconsistentNaming
private const int Format24bppRgb = (int)PixelFormat.Format24bppRgb;
/// <summary>
/// The integral representation of the 32bppArgb pixel format.
/// </summary>
// ReSharper disable once InconsistentNaming
private const int Format32bppArgb = (int)PixelFormat.Format32bppArgb;
/// <summary>
/// The integral representation of the 32bppPArgb pixel format.
/// </summary>
// ReSharper disable once InconsistentNaming
private const int Format32bppPArgb = (int)PixelFormat.Format32bppPArgb;
/// <summary>
/// The bitmap.
/// </summary>
@ -37,11 +61,6 @@ namespace ImageProcessor.Imaging
/// </summary>
private readonly int height;
/// <summary>
/// The size of the a single pixel.
/// </summary>
private readonly int pixelSize;
/// <summary>
/// The color channel - blue, green, red, alpha.
/// </summary>
@ -55,27 +74,27 @@ namespace ImageProcessor.Imaging
/// <summary>
/// The normal integral image.
/// </summary>
private readonly long[,] normalSumImage;
private long[,] normalSumImage;
/// <summary>
/// The squared integral image.
/// </summary>
private readonly long[,] squaredSumImage;
private long[,] squaredSumImage;
/// <summary>
/// The tilted sum image.
/// </summary>
private readonly long[,] tiltedSumImage;
private long[,] tiltedSumImage;
/// <summary>
/// The normal width.
/// </summary>
private readonly int normalWidth;
private int normalWidth;
/// <summary>
/// The tilted width.
/// </summary>
private readonly int tiltedWidth;
private int tiltedWidth;
/// <summary>
/// The number of bytes in a row.
@ -112,6 +131,11 @@ namespace ImageProcessor.Imaging
/// </summary>
private GCHandle tiltedSumHandle;
/// <summary>
/// The size of the color32 structure.
/// </summary>
private int pixelSize;
/// <summary>
/// The bitmap data.
/// </summary>
@ -153,46 +177,25 @@ namespace ImageProcessor.Imaging
/// </param>
public FastBitmap(Image bitmap, bool computeTilted)
{
int pixelFormat = (int)bitmap.PixelFormat;
// Check image format
if (!(bitmap.PixelFormat == PixelFormat.Format8bppIndexed ||
bitmap.PixelFormat == PixelFormat.Format24bppRgb ||
bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
bitmap.PixelFormat == PixelFormat.Format32bppPArgb))
if (!(pixelFormat == Format8bppIndexed ||
pixelFormat == Format24bppRgb ||
pixelFormat == Format32bppArgb ||
pixelFormat == Format32bppPArgb))
{
throw new ArgumentException("Only 8bpp, 24bpp and 32bpp images are supported.");
}
this.pixelSize = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8;
this.bitmap = (Bitmap)bitmap;
this.width = this.bitmap.Width;
this.height = this.bitmap.Height;
this.channel = this.bitmap.PixelFormat == PixelFormat.Format8bppIndexed ? 0 : 2;
this.computeTilted = computeTilted;
this.normalWidth = this.width + 1;
int normalHeight = this.height + 1;
this.tiltedWidth = this.width + 2;
int tiltedHeight = this.height + 2;
this.normalSumImage = new long[normalHeight, this.normalWidth];
this.normalSumHandle = GCHandle.Alloc(this.normalSumImage, GCHandleType.Pinned);
this.normalSum = (long*)this.normalSumHandle.AddrOfPinnedObject().ToPointer();
this.squaredSumImage = new long[normalHeight, this.normalWidth];
this.squaredSumHandle = GCHandle.Alloc(this.squaredSumImage, GCHandleType.Pinned);
this.squaredSum = (long*)this.squaredSumHandle.AddrOfPinnedObject().ToPointer();
if (this.computeTilted)
{
this.tiltedSumImage = new long[tiltedHeight, this.tiltedWidth];
this.tiltedSumHandle = GCHandle.Alloc(this.tiltedSumImage, GCHandleType.Pinned);
this.tiltedSum = (long*)this.tiltedSumHandle.AddrOfPinnedObject().ToPointer();
}
this.channel = pixelFormat == Format8bppIndexed ? 0 : 2;
this.computeTilted = computeTilted;
this.LockBitmap();
this.CalculateIntegrals();
}
/// <summary>
@ -260,13 +263,13 @@ namespace ImageProcessor.Imaging
/// <summary>
/// Allows the implicit conversion of an instance of <see cref="FastBitmap"/> to a
/// <see cref="Image"/>.
/// <see cref="System.Drawing.Image"/>.
/// </summary>
/// <param name="fastBitmap">
/// The instance of <see cref="FastBitmap"/> to convert.
/// </param>
/// <returns>
/// An instance of <see cref="Image"/>.
/// An instance of <see cref="System.Drawing.Image"/>.
/// </returns>
public static implicit operator Image(FastBitmap fastBitmap)
{
@ -308,14 +311,7 @@ namespace ImageProcessor.Imaging
}
#endif
Color32* data = this[x, y];
if (this.bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
this.bitmap.PixelFormat == PixelFormat.Format32bppPArgb)
{
return Color.FromArgb(data->A, data->R, data->G, data->B);
}
return Color.FromArgb(data->R, data->G, data->B);
return Color.FromArgb(data->A, data->R, data->G, data->B);
}
/// <summary>
@ -344,12 +340,7 @@ namespace ImageProcessor.Imaging
data->R = color.R;
data->G = color.G;
data->B = color.B;
if (this.bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
this.bitmap.PixelFormat == PixelFormat.Format32bppPArgb)
{
data->A = color.A;
}
data->A = color.A;
}
/// <summary>
@ -511,6 +502,7 @@ namespace ImageProcessor.Imaging
// 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.pixelSize = Image.GetPixelFormatSize(this.bitmap.PixelFormat) / 8;
this.bytesInARow = bounds.Width * this.pixelSize;
if (this.bytesInARow % 4 != 0)
{
@ -518,10 +510,34 @@ namespace ImageProcessor.Imaging
}
// Lock the bitmap
this.bitmapData = this.bitmap.LockBits(bounds, ImageLockMode.ReadWrite, this.bitmap.PixelFormat);
this.bitmapData = this.bitmap.LockBits(bounds, ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
// Set the value to the first scan line
this.pixelBase = (byte*)this.bitmapData.Scan0.ToPointer();
// Allocate values for integral image calculation.
this.normalWidth = this.width + 1;
int normalHeight = this.height + 1;
this.tiltedWidth = this.width + 2;
int tiltedHeight = this.height + 2;
this.normalSumImage = new long[normalHeight, this.normalWidth];
this.normalSumHandle = GCHandle.Alloc(this.normalSumImage, GCHandleType.Pinned);
this.normalSum = (long*)this.normalSumHandle.AddrOfPinnedObject().ToPointer();
this.squaredSumImage = new long[normalHeight, this.normalWidth];
this.squaredSumHandle = GCHandle.Alloc(this.squaredSumImage, GCHandleType.Pinned);
this.squaredSum = (long*)this.squaredSumHandle.AddrOfPinnedObject().ToPointer();
if (this.computeTilted)
{
this.tiltedSumImage = new long[tiltedHeight, this.tiltedWidth];
this.tiltedSumHandle = GCHandle.Alloc(this.tiltedSumImage, GCHandleType.Pinned);
this.tiltedSum = (long*)this.tiltedSumHandle.AddrOfPinnedObject().ToPointer();
}
this.CalculateIntegrals();
}
/// <summary>
@ -638,4 +654,4 @@ namespace ImageProcessor.Imaging
this.pixelBase = null;
}
}
}
}

5
src/ImageProcessor/Imaging/Filters/Artistic/HalftoneFilter.cs

@ -200,7 +200,8 @@ namespace ImageProcessor.Imaging.Filters.Artistic
// Yellow oversaturates the output.
int offset = this.distance;
float yellowMultiplier = this.distance * 1.667f;
float yellowMultiplier = this.distance * 1.334f;
float magentaMultiplier = this.distance * 1.667f;
float multiplier = this.distance * 2.2f;
float max = this.distance * (float)Math.Sqrt(2);
@ -289,7 +290,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
{
color = sourceBitmap.GetPixel(angledX, angledY);
cmykColor = color;
brushWidth = Math.Min((cmykColor.M / 100f) * multiplier, max);
brushWidth = Math.Min((cmykColor.M / 100f) * magentaMultiplier, max);
graphicsMagenta.FillEllipse(magentaBrush, angledX, angledY, brushWidth, brushWidth);
}

4
src/ImageProcessor/Imaging/Helpers/Adjustments.cs

@ -15,8 +15,6 @@ namespace ImageProcessor.Imaging.Helpers
using System.Drawing.Imaging;
using System.Threading.Tasks;
using ImageProcessor.Common.Extensions;
/// <summary>
/// Provides reusable adjustment methods to apply to images.
/// </summary>
@ -97,7 +95,7 @@ namespace ImageProcessor.Imaging.Helpers
}
float brightnessFactor = (float)threshold / 100;
Rectangle bounds = rectangle.HasValue ? rectangle.Value : new Rectangle(0, 0, source.Width, source.Height);
Rectangle bounds = rectangle ?? new Rectangle(0, 0, source.Width, source.Height);
ColorMatrix colorMatrix =
new ColorMatrix(

1
src/ImageProcessor/Imaging/Helpers/Effects.cs

@ -235,6 +235,7 @@ namespace ImageProcessor.Imaging.Helpers
// Darken it again to average out the color.
destination = Adjustments.Brightness(destination, -5);
return (Bitmap)destination;
}
}

3
src/ImageProcessor/Settings.StyleCop

@ -2,7 +2,9 @@
<GlobalSettings>
<CollectionProperty Name="RecognizedWords">
<Value>Accord</Value>
<Value>argb</Value>
<Value>bitstream</Value>
<Value>bpp</Value>
<Value>dd</Value>
<Value>ddd</Value>
<Value>dllimport</Value>
@ -13,6 +15,7 @@
<Value>mmmm</Value>
<Value>orig</Value>
<Value>quantizable</Value>
<Value>rgb</Value>
<Value>Scharr</Value>
<Value>Sobel</Value>
<Value>specifier</Value>

Loading…
Cancel
Save