diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 22ffe9fa39..65709a2e38 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -22,6 +22,7 @@ prompt 4 bin\Debug\ImageProcessor.XML + false pdbonly diff --git a/src/ImageProcessor/Processors/Filter.cs b/src/ImageProcessor/Processors/Filter.cs index b3c0d2756c..88cf22d1a0 100644 --- a/src/ImageProcessor/Processors/Filter.cs +++ b/src/ImageProcessor/Processors/Filter.cs @@ -7,10 +7,17 @@ namespace ImageProcessor.Processors { #region Using + + using System; using System.Collections.Generic; using System.Drawing; + using System.Drawing.Drawing2D; using System.Drawing.Imaging; + using System.IO; using System.Text.RegularExpressions; + using System.Web; + using System.Web.Hosting; + #endregion /// @@ -21,7 +28,18 @@ namespace ImageProcessor.Processors /// /// The regular expression to search strings for. /// - private static readonly Regex QueryRegex = new Regex(@"filter=(lomograph|polaroid|blackwhite|sepia|greyscale)", RegexOptions.Compiled); + private static readonly Regex QueryRegex = new Regex(@"filter=(lomograph|polaroid|blackwhite|sepia|greyscale|gotham|invert|hisatch|losatch|comic)", RegexOptions.Compiled); + + /// + /// Enumurates Argb colour channels. + /// + private enum ChannelArgb + { + Blue = 0, + Green = 1, + Red = 2, + Alpha = 3 + } #region IGraphicsProcessor Members /// @@ -141,7 +159,7 @@ namespace ImageProcessor.Processors switch ((string)this.DynamicParameter) { case "polaroid": - colorMatrix = ColorMatrixes.Poloroid; + colorMatrix = ColorMatrixes.Polaroid; break; case "lomograph": colorMatrix = ColorMatrixes.Lomograph; @@ -155,6 +173,21 @@ namespace ImageProcessor.Processors case "greyscale": colorMatrix = ColorMatrixes.GreyScale; break; + case "gotham": + colorMatrix = ColorMatrixes.Gotham; + break; + case "invert": + colorMatrix = ColorMatrixes.Invert; + break; + case "hisatch": + colorMatrix = ColorMatrixes.HiSatch; + break; + case "losatch": + colorMatrix = ColorMatrixes.LoSatch; + break; + case "comic": + colorMatrix = ColorMatrixes.LoSatch; + break; } using (Graphics graphics = Graphics.FromImage(newImage)) @@ -168,7 +201,110 @@ namespace ImageProcessor.Processors Rectangle rectangle = new Rectangle(0, 0, image.Width, image.Height); - graphics.DrawImage(image, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); + if (this.DynamicParameter == "comic") + { + // Set the attributes to LoSatch and draw the image. + graphics.DrawImage(image, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); + + // Create a bitmap for overlaying. + Bitmap hisatchBitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb); + + // Set the color matrix + attributes.SetColorMatrix(ColorMatrixes.HiSatch); + + // Draw the image with the hisatch colormatrix. + using (var g = Graphics.FromImage(hisatchBitmap)) + { + g.DrawImage(image, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); + } + + // We need to create a new image now with the hi saturation colormatrix and a pattern mask to paint it + // onto the other image with. + Bitmap patternBitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb); + + // Create the pattern mask. + using (var g = Graphics.FromImage(patternBitmap)) + { + g.Clear(Color.Black); + g.SmoothingMode = SmoothingMode.HighQuality; + for (var y = 0; y < image.Height; y += 10) + { + for (var x = 0; x < image.Width; x += 6) + { + g.FillEllipse(Brushes.White, x, y, 4, 4); + g.FillEllipse(Brushes.White, x + 3, y + 5, 4, 4); + } + } + } + + // Transfer the alpha channel from the mask to the hi sturation image. + TransferOneArgbChannelFromOneBitmapToAnother(patternBitmap, hisatchBitmap, ChannelArgb.Blue, ChannelArgb.Alpha); + + // Overlay the image. + graphics.DrawImage(hisatchBitmap, 0, 0); + + // Dispose of the other images + hisatchBitmap.Dispose(); + patternBitmap.Dispose(); + } + else + { + graphics.DrawImage(image, rectangle, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes); + + // Polaroid requires an extra tweak. + if (this.DynamicParameter == "polaroid") + { + using (GraphicsPath path = new GraphicsPath()) + { + path.AddEllipse(rectangle); + using (PathGradientBrush brush = new PathGradientBrush(path)) + { + // Fill a rectangle with an elliptical gradient brush that goes from orange to transparent. + // This has the effect of painting the far corners transparent and fading in to orange on the + // way in to the centre. + brush.WrapMode = WrapMode.Tile; + brush.CenterColor = Color.FromArgb(70, 255, 153, 102); + brush.SurroundColors = new Color[] { Color.FromArgb(0, 0, 0, 0) }; + + Blend blend = new Blend + { + Positions = new float[] { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0F }, + Factors = new float[] { 0.0f, 0.5f, 1f, 1f, 1.0f, 1.0f } + }; + + brush.Blend = blend; + + Region oldClip = graphics.Clip; + graphics.Clip = new Region(rectangle); + graphics.FillRectangle(brush, rectangle); + graphics.Clip = oldClip; + } + } + } + + // Gotham requires an extra tweak. + if (this.DynamicParameter == "gotham") + { + using (GraphicsPath path = new GraphicsPath()) + { + path.AddRectangle(rectangle); + + // Paint a burgundy rectangle with a transparency of ~30% over the image. + // Paint a blue rectangle with a transparency of 20% over the image. + using (SolidBrush brush = new SolidBrush(Color.FromArgb(77, 43, 4, 18))) + { + Region oldClip = graphics.Clip; + graphics.Clip = new Region(rectangle); + graphics.FillRectangle(brush, rectangle); + + // Fill the blue. + brush.Color = Color.FromArgb(51, 12, 22, 88); + graphics.FillRectangle(brush, rectangle); + graphics.Clip = oldClip; + } + } + } + } } } @@ -188,6 +324,71 @@ namespace ImageProcessor.Processors } #endregion + /// + /// Transfers a single ARGB channel from one image to another. + /// + /// + /// The source. + /// + /// + /// The destination. + /// + /// + /// The source channel. + /// + /// + /// The destination channel. + /// + private static void TransferOneArgbChannelFromOneBitmapToAnother(Bitmap source, Bitmap destination, ChannelArgb sourceChannel, ChannelArgb destinationChannel) + { + if (source.Size != destination.Size) + { + throw new ArgumentException(); + } + + Rectangle rectangle = new Rectangle(Point.Empty, source.Size); + + // Lockbits the source. + BitmapData bitmapDataSource = source.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + + // Declare an array to hold the bytes of the bitmap. + int bytes = bitmapDataSource.Stride * bitmapDataSource.Height; + + // Allocate a buffer for the source image + byte[] sourceRgbValues = new byte[bytes]; + + // Copy the RGB values into the array. + System.Runtime.InteropServices.Marshal.Copy(bitmapDataSource.Scan0, sourceRgbValues, 0, bytes); + + // Unlockbits the source. + source.UnlockBits(bitmapDataSource); + + // Lockbits the destination. + BitmapData bitmapDataDestination = destination.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + + // Allocate a buffer for image + byte[] destinationRgbValues = new byte[bytes]; + + // Copy the RGB values into the array. + System.Runtime.InteropServices.Marshal.Copy(bitmapDataDestination.Scan0, destinationRgbValues, 0, bytes); + + int s = (int)sourceChannel; + int d = (int)destinationChannel; + + for (int i = rectangle.Height * rectangle.Width; i > 0; i--) + { + destinationRgbValues[d] = sourceRgbValues[s]; + d += 4; + s += 4; + } + + // Copy the RGB values back to the bitmap + System.Runtime.InteropServices.Marshal.Copy(destinationRgbValues, 0, bitmapDataDestination.Scan0, bytes); + + // Unlock bits the destination. + destination.UnlockBits(bitmapDataDestination); + } + /// /// A list of available color matrices to apply to an image. /// @@ -232,20 +433,20 @@ namespace ImageProcessor.Processors } /// - /// Gets Poloroid. + /// Gets Polaroid. /// - internal static ColorMatrix Poloroid + internal static ColorMatrix Polaroid { get { return new ColorMatrix( new float[][] { - new float[] { 1.438f, -0.062f, -0.062f, 0, 0 }, + new float[] { 1.638f, -0.062f, -0.262f, 0, 0 }, new float[] { -0.122f, 1.378f, -0.122f, 0, 0 }, - new float[] { -0.016f, -0.016f, 1.483f, 0, 0 }, + new float[] { 1.016f, -0.016f, 1.383f, 0, 0 }, new float[] { 0, 0, 0, 1, 0 }, - new float[] { -0.03f, 0.05f, -0.02f, 0, 1 } + new float[] { 0.06f, -0.05f, -0.05f, 0, 1 } }); } } @@ -260,11 +461,11 @@ namespace ImageProcessor.Processors return new ColorMatrix( new float[][] { - new float[] { 1.25f, 0, 0, 0, 0 }, - new float[] { 0, 1.25f, 0, 0, 0 }, - new float[] { 0, 0, 0.94f, 0, 0 }, + new float[] { 1.50f, 0, 0, 0, 0 }, + new float[] { 0, 1.45f, 0, 0, 0 }, + new float[] { 0, 0, 1.09f, 0, 0 }, new float[] { 0, 0, 0, 1, 0 }, - new float[] { 0, 0, 0, 0, 1 } + new float[] { -0.10f, 0.05f, -0.08f, 0, 1 } }); } } @@ -287,6 +488,82 @@ namespace ImageProcessor.Processors }); } } + + /// + /// Gets Gotham. + /// + internal static ColorMatrix Gotham + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { .9f, .9f, .9f, 0, 0 }, + new float[] { .9f, .9f, .9f, 0, 0 }, + new float[] { .9f, .9f, .9f, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { -.5f, -.5f, -.45f, 0, 1 } + }); + } + } + + /// + /// Gets Invert. + /// + internal static ColorMatrix Invert + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { -1, 0, 0, 0, 0 }, + new float[] { 0, -1, 0, 0, 0 }, + new float[] { 0, 0, -1, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { 1, 1, 1, 0, 1 } + }); + } + } + + /// + /// Gets HiSatch. + /// + internal static ColorMatrix HiSatch + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { 3, -1, -1, 0, 0 }, + new float[] { -1, 3, -1, 0, 0 }, + new float[] { -1, -1, 3, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { 0, 0, 0, 0, 1 } + }); + } + } + + /// + /// Gets LoSatch. + /// + internal static ColorMatrix LoSatch + { + get + { + return new ColorMatrix( + new float[][] + { + new float[] { 1, 0, 0, 0, 0 }, + new float[] { 0, 1, 0, 0, 0 }, + new float[] { 0, 0, 1, 0, 0 }, + new float[] { 0, 0, 0, 1, 0 }, + new float[] { .25f, .25f, .25f, 0, 1 } + }); + } + } } } } diff --git a/src/Test/Test/Test.csproj b/src/Test/Test/Test.csproj index 3b61c60faf..ff800dd95b 100644 --- a/src/Test/Test/Test.csproj +++ b/src/Test/Test/Test.csproj @@ -122,7 +122,9 @@ - + + Designer + Web.config diff --git a/src/Test/Test/Web.config b/src/Test/Test/Web.config index b400b2c812..0f037fa209 100644 --- a/src/Test/Test/Web.config +++ b/src/Test/Test/Web.config @@ -1,117 +1,117 @@ - - - - - - - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +