Browse Source

Finishing Mask plus BGColor fix

Former-commit-id: 1f45b8cf79700436d535eb97857253222bacc574
Former-commit-id: 5bf2d026598facc3e4ce8b1f45e2d80d8e1175c1
pull/17/head
James South 12 years ago
parent
commit
81e09be64e
  1. 12
      src/ImageProcessor.Playground/Program.cs
  2. BIN
      src/ImageProcessor.Playground/images/input/mask.png
  3. 14
      src/ImageProcessor/ImageFactory.cs
  4. 60
      src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
  5. 71
      src/ImageProcessor/Imaging/Helpers/Effects.cs
  6. 40
      src/ImageProcessor/Imaging/Helpers/ImageMaths.cs
  7. 7
      src/ImageProcessor/Processors/BackgroundColor.cs
  8. 1
      src/ImageProcessor/Processors/Filter.cs
  9. 41
      src/ImageProcessor/Processors/Mask.cs

12
src/ImageProcessor.Playground/Program.cs

@ -18,15 +18,19 @@ namespace ImageProcessor.PlayGround
using System.Linq;
using ImageProcessor;
using ImageProcessor.Configuration;
using ImageProcessor.Imaging;
using ImageProcessor.Imaging.Filters.EdgeDetection;
using ImageProcessor.Imaging.Filters.Photo;
using ImageProcessor.Imaging.Formats;
/// <summary>
/// The program.
/// </summary>
public class Program
{
protected static readonly IEnumerable<ISupportedImageFormat> formats = ImageProcessorBootstrapper.Instance.SupportedImageFormats;
/// <summary>
/// The main routine.
/// </summary>
@ -45,6 +49,7 @@ namespace ImageProcessor.PlayGround
di.Create();
}
Image mask = Image.FromFile(Path.Combine(resolvedPath, "mask.png"));
IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".jpg");
//IEnumerable<FileInfo> files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png", ".tif");
@ -73,15 +78,16 @@ namespace ImageProcessor.PlayGround
//.BackgroundColor(Color.White)
//.Resize(new Size((int)(size.Width * 1.1), 0))
//.ContentAwareResize(layer)
.Constrain(size)
.Mask()
//.Constrain(size)
//.Mask(mask)
//.BackgroundColor(Color.HotPink)
//.ReplaceColor(Color.FromArgb(255, 1, 107, 165), Color.FromArgb(255, 1, 165, 13), 80)
//.Resize(layer)
//.DetectEdges(new SobelEdgeFilter(), false)
//.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.EntropyCrop()
//.Filter(MatrixFilters.Invert)
//.Filter(MatrixFilters.Comic)
.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.HiSatch)
//.Pixelate(8)
//.GaussianSharpen(10)

BIN
src/ImageProcessor.Playground/images/input/mask.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

14
src/ImageProcessor/ImageFactory.cs

@ -670,11 +670,21 @@ namespace ImageProcessor
return this;
}
public ImageFactory Mask()
/// <summary>
/// Applies the given image mask to the current image. If the mask is not the same size as the image
/// it will be centered against the image.
/// </summary>
/// <param name="imageMask">
/// The image containing the mask to apply.
/// </param>
/// <returns>
/// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class.
/// </returns>
public ImageFactory Mask(Image imageMask)
{
if (this.ShouldProcess)
{
Mask mask = new Mask();
Mask mask = new Mask { DynamicParameter = imageMask };
this.CurrentImageFormat.ApplyProcessor(mask.ProcessImage, this);
}

60
src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs

@ -10,7 +10,6 @@
namespace ImageProcessor.Imaging.Filters.Photo
{
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
@ -106,8 +105,8 @@ namespace ImageProcessor.Imaging.Filters.Photo
}
}
// Transfer the alpha channel from the mask to the high saturation image.
ApplyMask(patternBitmap, lowBitmap);
// Transfer the alpha channel from the mask to the low saturation image.
lowBitmap = Effects.ApplyMask(lowBitmap, patternBitmap);
using (Graphics graphics = Graphics.FromImage(newImage))
{
@ -195,8 +194,8 @@ namespace ImageProcessor.Imaging.Filters.Photo
using (Bitmap temp = filter.Process2DFilter(source))
{
destination = new InvertMatrixFilter().TransformImage(temp, destination);
// Darken it slightly
// Darken it slightly to aid detection
destination = Adjustments.Brightness(destination, -5);
}
@ -222,56 +221,9 @@ namespace ImageProcessor.Imaging.Filters.Photo
});
}
// Darken it again to average out the color.
destination = Adjustments.Brightness(destination, -5);
return (Bitmap)destination;
}
/// <summary>
/// Applies a mask .
/// </summary>
/// <param name="source">
/// The source.
/// </param>
/// <param name="destination">
/// The destination.
/// </param>
/// <exception cref="ArgumentException">
/// Thrown if the two images are of different size.
/// </exception>
private static void ApplyMask(Image source, Image destination)
{
if (source.Size != destination.Size)
{
throw new ArgumentException();
}
using (FastBitmap sourceBitmap = new FastBitmap(source))
{
using (FastBitmap destinationBitmap = new FastBitmap(destination))
{
int width = source.Width;
int height = source.Height;
Parallel.For(
0,
height,
y =>
{
for (int x = 0; x < width; x++)
{
// ReSharper disable AccessToDisposedClosure
Color sourceColor = sourceBitmap.GetPixel(x, y);
Color destinationColor = destinationBitmap.GetPixel(x, y);
if (destinationColor.A != 0)
{
destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceColor.B, destinationColor.R, destinationColor.G, destinationColor.B));
}
// ReSharper restore AccessToDisposedClosure
}
});
}
}
}
}
}

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

@ -13,6 +13,7 @@ namespace ImageProcessor.Imaging.Helpers
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Threading.Tasks;
/// <summary>
/// Provides reusable effect methods to apply to images.
@ -69,8 +70,8 @@ namespace ImageProcessor.Imaging.Helpers
}
else
{
centerColor = Color.FromArgb(0, baseColor.R, baseColor.G, baseColor.B);
edgeColor = Color.FromArgb(255, baseColor.R, baseColor.G, baseColor.B);
centerColor = Color.FromArgb(0, baseColor.R, baseColor.G, baseColor.B);
edgeColor = Color.FromArgb(255, baseColor.R, baseColor.G, baseColor.B);
}
brush.WrapMode = WrapMode.Tile;
@ -108,5 +109,71 @@ namespace ImageProcessor.Imaging.Helpers
{
return Vignette(source, baseColor, rectangle, true);
}
/// <summary>
/// Applies the given image mask to the source.
/// </summary>
/// <param name="source">
/// The source <see cref="Image"/>.
/// </param>
/// <param name="mask">
/// The mask <see cref="Image"/>.
/// </param>
/// <exception cref="ArgumentException">
/// Thrown if the two images are of different size.
/// </exception>
/// <returns>
/// The masked <see cref="Bitmap"/>.
/// </returns>
public static Bitmap ApplyMask(Image source, Image mask)
{
if (mask.Size != source.Size)
{
throw new ArgumentException();
}
int width = mask.Width;
int height = mask.Height;
Bitmap toMask = new Bitmap(source);
// Loop through and replace the alpha channel
using (FastBitmap maskBitmap = new FastBitmap(mask))
{
using (FastBitmap sourceBitmap = new FastBitmap(toMask))
{
Parallel.For(
0,
height,
y =>
{
for (int x = 0; x < width; x++)
{
// ReSharper disable AccessToDisposedClosure
Color maskColor = maskBitmap.GetPixel(x, y);
Color sourceColor = sourceBitmap.GetPixel(x, y);
if (sourceColor.A != 0)
{
sourceBitmap.SetPixel(x, y, Color.FromArgb(maskColor.B, sourceColor.R, sourceColor.G, sourceColor.B));
}
// ReSharper restore AccessToDisposedClosure
}
});
}
}
// Ensure the background is cleared out on non alpha supporting formats.
Bitmap clear = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(clear))
{
graphics.Clear(Color.Transparent);
graphics.DrawImage(toMask, 0, 0, width, height);
}
toMask.Dispose();
return clear;
}
}
}

40
src/ImageProcessor/Imaging/Helpers/ImageMaths.cs

@ -15,7 +15,7 @@ namespace ImageProcessor.Imaging.Helpers
/// <summary>
/// Provides reusable mathematical methods to apply to images.
/// </summary>
public class ImageMaths
public static class ImageMaths
{
/// <summary>
/// Gets the bounding <see cref="Rectangle"/> from the given points.
@ -29,13 +29,13 @@ namespace ImageProcessor.Imaging.Helpers
/// <returns>
/// The bounding <see cref="Rectangle"/>.
/// </returns>
public Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight)
public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight)
{
return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
}
/// <summary>
/// Gets a <see cref="Rectangle"/> centered within it's parent.
/// Gets a <see cref="Rectangle"/> representing the child centered relative to the parent.
/// </summary>
/// <param name="parent">
/// The parent <see cref="Rectangle"/>.
@ -46,17 +46,33 @@ namespace ImageProcessor.Imaging.Helpers
/// <returns>
/// The centered <see cref="Rectangle"/>.
/// </returns>
public Rectangle CenteredRectangle(Rectangle parent, Rectangle child)
public static RectangleF CenteredRectangle(Rectangle parent, Rectangle child)
{
if (parent.Size.Width < child.Size.Width && parent.Size.Height < child.Size.Height)
{
return parent;
}
int x = (parent.Width - child.Width) / 2;
int y = (parent.Height - child.Height) / 2;
float x = (parent.Width - child.Width) / 2.0F;
float y = (parent.Height - child.Height) / 2.0F;
int width = child.Width;
int height = child.Height;
return new RectangleF(x, y, width, height);
}
return new Rectangle(x, y, child.Width, child.Height);
/// <summary>
/// Returns the array of <see cref="Point"/> matching the bounds of the given rectangle.
/// </summary>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> to return the points from.
/// </param>
/// <returns>
/// The <see cref="Point"/> array.
/// </returns>
public static Point[] ToPoints(Rectangle rectangle)
{
return new[]
{
new Point(rectangle.Left, rectangle.Top),
new Point(rectangle.Right, rectangle.Top),
new Point(rectangle.Right, rectangle.Bottom),
new Point(rectangle.Left, rectangle.Bottom)
};
}
}
}

7
src/ImageProcessor/Processors/BackgroundColor.cs

@ -55,8 +55,11 @@ namespace ImageProcessor.Processors
try
{
int width = image.Width;
int height = image.Height;
Color backgroundColor = this.DynamicParameter;
newImage = new Bitmap(image.Width, image.Height);
newImage = new Bitmap(width, height);
// Make a graphics object from the empty bitmap.
using (Graphics graphics = Graphics.FromImage(newImage))
@ -65,7 +68,7 @@ namespace ImageProcessor.Processors
graphics.Clear(backgroundColor);
// Draw passed in image onto graphics object.
graphics.DrawImage(image, 0, 0);
graphics.DrawImage(image, 0, 0, width, height);
}
image.Dispose();

1
src/ImageProcessor/Processors/Filter.cs

@ -13,7 +13,6 @@ namespace ImageProcessor.Processors
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using ImageProcessor.Common.Exceptions;
using ImageProcessor.Imaging.Filters.Photo;

41
src/ImageProcessor/Processors/Mask.cs

@ -15,9 +15,11 @@ namespace ImageProcessor.Processors
using System.Drawing;
using ImageProcessor.Common.Exceptions;
using ImageProcessor.Imaging.Helpers;
/// <summary>
/// Applies a mask to the given image.
/// Applies a mask to the given image. If the mask is not the same size as the image
/// it will be centered against the image.
/// </summary>
public class Mask : IGraphicsProcessor
{
@ -60,29 +62,46 @@ namespace ImageProcessor.Processors
public Image ProcessImage(ImageFactory factory)
{
Bitmap newImage = null;
Bitmap mask = null;
Bitmap maskResized = null;
Image image = factory.Image;
Size original = image.Size;
Size smaller = new Size(image.Width / 2, image.Height / 2);
int x = (original.Width - smaller.Width) / 2;
int y = (original.Height - smaller.Height) / 2;
int width = image.Width;
int height = image.Height;
try
{
newImage = new Bitmap(original.Width, image.Height);
int width = image.Width;
int height = image.Height;
mask = new Bitmap(this.DynamicParameter);
Rectangle parent = new Rectangle(0, 0, width, height);
Rectangle child = new Rectangle(0, 0, mask.Width, mask.Height);
RectangleF centered = ImageMaths.CenteredRectangle(parent, child);
using (Graphics graphics = Graphics.FromImage(newImage))
// Resize the mask to the size of the input image so that we can apply it.
maskResized = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(maskResized))
{
graphics.DrawImage(image, x, y, smaller.Width, smaller.Height);
graphics.Clear(Color.Transparent);
graphics.DrawImage(mask, new PointF(centered.X, centered.Y));
}
newImage = Effects.ApplyMask(image, maskResized);
mask.Dispose();
maskResized.Dispose();
image.Dispose();
image = newImage;
}
catch (Exception ex)
{
if (mask != null)
{
mask.Dispose();
}
if (maskResized != null)
{
maskResized.Dispose();
}
if (newImage != null)
{
newImage.Dispose();

Loading…
Cancel
Save