diff --git a/src/ImageProcessor.Playground/Program.cs b/src/ImageProcessor.Playground/Program.cs index 937909347..361cf8aab 100644 --- a/src/ImageProcessor.Playground/Program.cs +++ b/src/ImageProcessor.Playground/Program.cs @@ -108,7 +108,7 @@ namespace ImageProcessor.PlayGround //.DetectEdges(new Laplacian3X3EdgeFilter(), true) //.DetectEdges(new LaplacianOfGaussianEdgeFilter()) //.EntropyCrop() - .Halftone() + .Halftone(true) //.Filter(MatrixFilters.Invert) //.Contrast(50) //.Filter(MatrixFilters.Comic) diff --git a/src/ImageProcessor/ImageFactory.cs b/src/ImageProcessor/ImageFactory.cs index 0d07129e3..2950ad195 100644 --- a/src/ImageProcessor/ImageFactory.cs +++ b/src/ImageProcessor/ImageFactory.cs @@ -681,11 +681,20 @@ namespace ImageProcessor return this; } - public ImageFactory Halftone() + /// + /// Converts the current image to a CMYK halftone representation of that image. + /// + /// + /// Whether to trace over the current image and add borders to add a comic book effect. + /// + /// + /// The current instance of the class. + /// + public ImageFactory Halftone(bool comicMode = false) { if (this.ShouldProcess) { - Halftone halftone = new Halftone(); + Halftone halftone = new Halftone { DynamicParameter = comicMode }; this.CurrentImageFormat.ApplyProcessor(halftone.ProcessImage, this); } diff --git a/src/ImageProcessor/Imaging/Filters/Artistic/HalftoneFilter.cs b/src/ImageProcessor/Imaging/Filters/Artistic/HalftoneFilter.cs index 43669cec1..a6b8cc7a1 100644 --- a/src/ImageProcessor/Imaging/Filters/Artistic/HalftoneFilter.cs +++ b/src/ImageProcessor/Imaging/Filters/Artistic/HalftoneFilter.cs @@ -37,6 +37,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic /// /// The angle of the yellow component in degrees. /// + // ReSharper disable once RedundantDefaultMemberInitializer private float yellowAngle = 0f; /// @@ -184,7 +185,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic float max = this.distance; // Bump up the keyline max so that black looks black. - float keylineMax = max + ((float)Math.Sqrt(2) * 1.5f); + float keylineMax = max + ((float)Math.Sqrt(2) * 1.44f); // Color sampled process colours from Wikipedia pages. // Keyline brush is declared separately. @@ -239,9 +240,11 @@ namespace ImageProcessor.Imaging.Filters.Artistic Color color; CmykColor cmykColor; float brushWidth; + int offsetX = x - (d >> 1); + int offsetY = y - (d >> 1); // Cyan - Point rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.cyanAngle, center); + Point rotatedPoint = ImageMaths.RotatePoint(new Point(offsetX, offsetY), this.cyanAngle, center); int angledX = rotatedPoint.X; int angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) @@ -253,7 +256,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic } // Magenta - rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.magentaAngle, center); + rotatedPoint = ImageMaths.RotatePoint(new Point(offsetX, offsetY), this.magentaAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) @@ -265,7 +268,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic } // Yellow - rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.yellowAngle, center); + rotatedPoint = ImageMaths.RotatePoint(new Point(offsetX, offsetY), this.yellowAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) @@ -277,7 +280,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic } // Keyline - rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.keylineAngle, center); + rotatedPoint = ImageMaths.RotatePoint(new Point(offsetX, offsetY), this.keylineAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) @@ -321,7 +324,10 @@ namespace ImageProcessor.Imaging.Filters.Artistic Color keylinePixel = keylineBitmap.GetPixel(x, y); CmykColor blended = cyanPixel.AddAsCmykColor(magentaPixel, yellowPixel, keylinePixel); - destinationBitmap.SetPixel(x, y, blended); + if (rectangle.Contains(new Point(x, y))) + { + destinationBitmap.SetPixel(x, y, blended); + } // ReSharper restore AccessToDisposedClosure } }); diff --git a/src/ImageProcessor/Processors/Halftone.cs b/src/ImageProcessor/Processors/Halftone.cs index 1dea5b68c..995f47cbc 100644 --- a/src/ImageProcessor/Processors/Halftone.cs +++ b/src/ImageProcessor/Processors/Halftone.cs @@ -13,7 +13,6 @@ namespace ImageProcessor.Processors using System; using System.Collections.Generic; using System.Drawing; - using System.Drawing.Imaging; using System.Threading.Tasks; using ImageProcessor.Common.Exceptions; @@ -70,43 +69,48 @@ namespace ImageProcessor.Processors int width = image.Width; int height = image.Height; Bitmap newImage = null; - //Bitmap edgeBitmap = null; + Bitmap edgeBitmap = null; try { HalftoneFilter filter = new HalftoneFilter(5); newImage = new Bitmap(image); newImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); newImage = filter.ApplyFilter(newImage); + bool comicMode = this.DynamicParameter; - // Draw the edges. - //edgeBitmap = new Bitmap(width, height); - //edgeBitmap.SetResolution(image.HorizontalResolution, image.VerticalResolution); - //edgeBitmap = Trace(image, edgeBitmap, 120); - - using (Graphics graphics = Graphics.FromImage(newImage)) + if (comicMode) { - // Overlay the image. - //graphics.DrawImage(edgeBitmap, 0, 0); - Rectangle rectangle = new Rectangle(0, 0, width, height); - - // Draw an edge around the image. - //using (Pen blackPen = new Pen(Color.Black)) - //{ - // blackPen.Width = 4; - // graphics.DrawRectangle(blackPen, rectangle); - //} + // Draw the edges. + edgeBitmap = new Bitmap(width, height); + edgeBitmap.SetResolution(image.HorizontalResolution, image.VerticalResolution); + edgeBitmap = Trace(image, edgeBitmap, 120); + + using (Graphics graphics = Graphics.FromImage(newImage)) + { + // Overlay the image. + graphics.DrawImage(edgeBitmap, 0, 0); + Rectangle rectangle = new Rectangle(0, 0, width, height); + + // Draw an edge around the image. + using (Pen blackPen = new Pen(Color.Black)) + { + blackPen.Width = 4; + graphics.DrawRectangle(blackPen, rectangle); + } + } + + edgeBitmap.Dispose(); } - //edgeBitmap.Dispose(); image.Dispose(); image = newImage; } catch (Exception ex) { - //if (edgeBitmap != null) - //{ - // edgeBitmap.Dispose(); - //} + if (edgeBitmap != null) + { + edgeBitmap.Dispose(); + } if (newImage != null) {