// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. // // -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Processors { using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using ImageProcessor.Common.Exceptions; using ImageProcessor.Imaging; using ImageProcessor.Imaging.Filters.Binarization; using ImageProcessor.Imaging.Filters.EdgeDetection; /// /// Performs a crop on an image to the area of greatest entropy. /// public class EntropyCrop : IGraphicsProcessor { /// /// Initializes a new instance of the class. /// public EntropyCrop() { this.Settings = new Dictionary(); } /// /// Gets or sets the dynamic parameter. /// public dynamic DynamicParameter { get; set; } /// /// Gets or sets any additional settings required by the processor. /// public Dictionary Settings { get; set; } /// /// Processes the image. /// /// /// The current instance of the class containing /// the image to process. /// /// /// The processed image from the current instance of the class. /// public Image ProcessImage(ImageFactory factory) { Bitmap newImage = null; Bitmap grey = null; Image image = factory.Image; byte threshold = this.DynamicParameter; try { grey = new ConvolutionFilter(new SobelEdgeFilter(), true).ProcessFilter((Bitmap)image); grey = new BinaryThreshold(threshold).ProcessFilter(grey); Rectangle rectangle = this.FindBoundingBox(grey, 0); newImage = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format32bppPArgb); using (Graphics graphics = Graphics.FromImage(newImage)) { graphics.DrawImage( image, new Rectangle(0, 0, rectangle.Width, rectangle.Height), rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, GraphicsUnit.Pixel); } // Reassign the image. grey.Dispose(); image.Dispose(); image = newImage; } catch (Exception ex) { if (grey != null) { grey.Dispose(); } if (newImage != null) { newImage.Dispose(); } throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex); } return image; } /// /// Finds the bounding rectangle based on the first instance of any color component other /// than the given one. /// /// /// The bitmap. /// /// /// The color component to remove. /// /// /// The . /// private Rectangle FindBoundingBox(Bitmap bitmap, byte componentToRemove) { int width = bitmap.Width; int height = bitmap.Height; int startX; int startY; int stopX; int stopY; Func getMinY = fastBitmap => { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (fastBitmap.GetPixel(x, y).B != componentToRemove) { return y; } } } return 0; }; Func getMaxY = fastBitmap => { for (int y = height - 1; y > -1; y--) { for (int x = 0; x < width; x++) { if (fastBitmap.GetPixel(x, y).B != componentToRemove) { return y; } } } return height; }; Func getMinX = fastBitmap => { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (fastBitmap.GetPixel(x, y).B != componentToRemove) { return x; } } } return 0; }; Func getMaxX = fastBitmap => { for (int x = width - 1; x > -1; x--) { for (int y = 0; y < height; y++) { if (fastBitmap.GetPixel(x, y).B != componentToRemove) { return x; } } } return height; }; using (FastBitmap fastBitmap = new FastBitmap(bitmap)) { startY = getMinY(fastBitmap); stopY = getMaxY(fastBitmap); startX = getMinX(fastBitmap); stopX = getMaxX(fastBitmap); } return new Rectangle(startX + 1, startY + 1, stopX - (startX + 1), stopY - (startY + 1)); } } }