/// <summary> /// Finds the bounding rectangle based on the first instance of any color component other /// than the given one. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <param name="bitmap">The <see cref="Image"/> to search within.</param> /// <param name="componentValue">The color component value to remove.</param> /// <param name="channel">The <see cref="RgbaComponent"/> channel to test against.</param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> public static Rectangle GetFilteredBoundingRectangle <TColor>(ImageBase <TColor> bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) where TColor : struct, IPixel <TColor> { int width = bitmap.Width; int height = bitmap.Height; Point topLeft = default(Point); Point bottomRight = default(Point); Func <PixelAccessor <TColor>, int, int, float, bool> delegateFunc; // Determine which channel to check against switch (channel) { case RgbaComponent.R: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().X - b) > Constants.Epsilon; break; case RgbaComponent.G: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Y - b) > Constants.Epsilon; break; case RgbaComponent.B: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Z - b) > Constants.Epsilon; break; default: delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().W - b) > Constants.Epsilon; break; } Func <PixelAccessor <TColor>, int> getMinY = pixels => { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { if (delegateFunc(pixels, x, y, componentValue)) { return(y); } } } return(0); }; Func <PixelAccessor <TColor>, int> getMaxY = pixels => { for (int y = height - 1; y > -1; y--) { for (int x = 0; x < width; x++) { if (delegateFunc(pixels, x, y, componentValue)) { return(y); } } } return(height); }; Func <PixelAccessor <TColor>, int> getMinX = pixels => { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (delegateFunc(pixels, x, y, componentValue)) { return(x); } } } return(0); }; Func <PixelAccessor <TColor>, int> getMaxX = pixels => { for (int x = width - 1; x > -1; x--) { for (int y = 0; y < height; y++) { if (delegateFunc(pixels, x, y, componentValue)) { return(x); } } } return(height); }; using (PixelAccessor <TColor> bitmapPixels = bitmap.Lock()) { topLeft.Y = getMinY(bitmapPixels); topLeft.X = getMinX(bitmapPixels); bottomRight.Y = (getMaxY(bitmapPixels) + 1).Clamp(0, height); bottomRight.X = (getMaxX(bitmapPixels) + 1).Clamp(0, width); } return(GetBoundingRectangle(topLeft, bottomRight)); }
/// <summary> /// Copies the properties from the other <see cref="ImageBase{TColor, TPacked}"/>. /// </summary> /// <param name="other"> /// The other <see cref="ImageBase{TColor, TPacked}"/> to copy the properties from. /// </param> protected void CopyProperties(ImageBase <TColor, TPacked> other) { this.Quality = other.Quality; this.FrameDelay = other.FrameDelay; }
/// <summary> /// Initializes a new instance of the <see cref="Image{TColor}"/> class /// by making a copy from another image. /// </summary> /// <param name="other">The other image, where the clone should be made from.</param> /// <exception cref="System.ArgumentNullException"><paramref name="other"/> is null.</exception> public Image(ImageBase <TColor> other) : base(other) { this.CopyProperties(other); }
/// <summary> /// Initializes a new instance of the <see cref="Image{TPixel}"/> class /// by making a copy from another image. /// </summary> /// <param name="other">The other image, where the clone should be made from.</param> /// <exception cref="System.ArgumentNullException"><paramref name="other"/> is null.</exception> public Image(ImageBase <TPixel> other) : base(other) { this.MetaData = new ImageMetaData(); }
/// <summary> /// Initializes a new instance of the <see cref="PixelAccessor"/> class. /// </summary> /// <param name="image">The image to provide pixel access for.</param> public PixelAccessor(ImageBase <Color, uint> image) : base(image) { }
/// <summary> /// Initializes a new instance of the <see cref="Image{TPixel}"/> class /// by making a copy from another image. /// </summary> /// <param name="other">The other image, where the clone should be made from.</param> /// <exception cref="System.ArgumentNullException"><paramref name="other"/> is null.</exception> public Image(ImageBase <TPixel> other) : base(other) { }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TColor}"/> class. /// </summary> /// <param name="image">The image to create the frame from.</param> public ImageFrame(ImageBase <TColor> image) : base(image) { }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TPixel}"/> class. /// </summary> /// <param name="image">The image to create the frame from.</param> public ImageFrame(ImageBase <TPixel> image) : base(image) { }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TColor, TPacked}"/> class. /// </summary> /// <param name="image">The image to create the frame from.</param> public ImageFrame(ImageBase <TColor, TPacked> image) : base(image) { }
/// <summary> /// Copies the properties from the other <see cref="ImageBase{TColor}"/>. /// </summary> /// <param name="other"> /// The other <see cref="ImageBase{TColor}"/> to copy the properties from. /// </param> protected void CopyProperties(ImageBase <TColor> other) { this.Configuration = other.Configuration; this.Quality = other.Quality; this.FrameDelay = other.FrameDelay; }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame"/> class. /// </summary> /// <param name="image"> /// The image to create the frame from. /// </param> public ImageFrame(ImageBase <Color, uint> image) : base(image) { }
/// <summary> /// Calculates the target rectangle for crop mode. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam> /// <param name="source">The source image.</param> /// <param name="options">The resize options.</param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> private static Rectangle CalculateCropRectangle <TColor, TPacked>(ImageBase <TColor, TPacked> source, ResizeOptions options) where TColor : struct, IPackedPixel <TPacked> where TPacked : struct { int width = options.Size.Width; int height = options.Size.Height; if (width <= 0 || height <= 0) { return(new Rectangle(0, 0, source.Width, source.Height)); } double ratio; int sourceWidth = source.Width; int sourceHeight = source.Height; int destinationX = 0; int destinationY = 0; int destinationWidth = width; int destinationHeight = height; // Fractional variants for preserving aspect ratio. double percentHeight = Math.Abs(height / (double)sourceHeight); double percentWidth = Math.Abs(width / (double)sourceWidth); if (percentHeight < percentWidth) { ratio = percentWidth; if (options.CenterCoordinates.Any()) { double center = -(ratio * sourceHeight) * options.CenterCoordinates.First(); destinationY = (int)center + (height / 2); if (destinationY > 0) { destinationY = 0; } if (destinationY < (int)(height - (sourceHeight * ratio))) { destinationY = (int)(height - (sourceHeight * ratio)); } } else { switch (options.Position) { case AnchorPosition.Top: case AnchorPosition.TopLeft: case AnchorPosition.TopRight: destinationY = 0; break; case AnchorPosition.Bottom: case AnchorPosition.BottomLeft: case AnchorPosition.BottomRight: destinationY = (int)(height - (sourceHeight * ratio)); break; default: destinationY = (int)((height - (sourceHeight * ratio)) / 2); break; } } destinationHeight = (int)Math.Ceiling(sourceHeight * percentWidth); } else { ratio = percentHeight; if (options.CenterCoordinates.Any()) { double center = -(ratio * sourceWidth) * options.CenterCoordinates.ToArray()[1]; destinationX = (int)center + (width / 2); if (destinationX > 0) { destinationX = 0; } if (destinationX < (int)(width - (sourceWidth * ratio))) { destinationX = (int)(width - (sourceWidth * ratio)); } } else { switch (options.Position) { case AnchorPosition.Left: case AnchorPosition.TopLeft: case AnchorPosition.BottomLeft: destinationX = 0; break; case AnchorPosition.Right: case AnchorPosition.TopRight: case AnchorPosition.BottomRight: destinationX = (int)(width - (sourceWidth * ratio)); break; default: destinationX = (int)((width - (sourceWidth * ratio)) / 2); break; } } destinationWidth = (int)Math.Ceiling(sourceWidth * percentHeight); } return(new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight)); }
/// <summary> /// Calculates the target rectangle for box pad mode. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam> /// <param name="source">The source image.</param> /// <param name="options">The resize options.</param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> private static Rectangle CalculateBoxPadRectangle <TColor, TPacked>(ImageBase <TColor, TPacked> source, ResizeOptions options) where TColor : struct, IPackedPixel <TPacked> where TPacked : struct { int width = options.Size.Width; int height = options.Size.Height; if (width <= 0 || height <= 0) { return(new Rectangle(0, 0, source.Width, source.Height)); } int sourceWidth = source.Width; int sourceHeight = source.Height; // Fractional variants for preserving aspect ratio. double percentHeight = Math.Abs(height / (double)sourceHeight); double percentWidth = Math.Abs(width / (double)sourceWidth); int boxPadHeight = height > 0 ? height : Convert.ToInt32(sourceHeight * percentWidth); int boxPadWidth = width > 0 ? width : Convert.ToInt32(sourceWidth * percentHeight); // Only calculate if upscaling. if (sourceWidth < boxPadWidth && sourceHeight < boxPadHeight) { int destinationX; int destinationY; int destinationWidth = sourceWidth; int destinationHeight = sourceHeight; width = boxPadWidth; height = boxPadHeight; switch (options.Position) { case AnchorPosition.Left: destinationY = (height - sourceHeight) / 2; destinationX = 0; break; case AnchorPosition.Right: destinationY = (height - sourceHeight) / 2; destinationX = width - sourceWidth; break; case AnchorPosition.TopRight: destinationY = 0; destinationX = width - sourceWidth; break; case AnchorPosition.Top: destinationY = 0; destinationX = (width - sourceWidth) / 2; break; case AnchorPosition.TopLeft: destinationY = 0; destinationX = 0; break; case AnchorPosition.BottomRight: destinationY = height - sourceHeight; destinationX = width - sourceWidth; break; case AnchorPosition.Bottom: destinationY = height - sourceHeight; destinationX = (width - sourceWidth) / 2; break; case AnchorPosition.BottomLeft: destinationY = height - sourceHeight; destinationX = 0; break; default: destinationY = (height - sourceHeight) / 2; destinationX = (width - sourceWidth) / 2; break; } return(new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight)); } // Switch to pad mode to downscale and calculate from there. return(CalculatePadRectangle(source, options)); }
/// <summary> /// Calculates the target rectangle for pad mode. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam> /// <param name="source">The source image.</param> /// <param name="options">The resize options.</param> /// <returns> /// The <see cref="Rectangle"/>. /// </returns> private static Rectangle CalculatePadRectangle <TColor, TPacked>(ImageBase <TColor, TPacked> source, ResizeOptions options) where TColor : struct, IPackedPixel <TPacked> where TPacked : struct { int width = options.Size.Width; int height = options.Size.Height; if (width <= 0 || height <= 0) { return(new Rectangle(0, 0, source.Width, source.Height)); } double ratio; int sourceWidth = source.Width; int sourceHeight = source.Height; int destinationX = 0; int destinationY = 0; int destinationWidth = width; int destinationHeight = height; // Fractional variants for preserving aspect ratio. double percentHeight = Math.Abs(height / (double)sourceHeight); double percentWidth = Math.Abs(width / (double)sourceWidth); if (percentHeight < percentWidth) { ratio = percentHeight; destinationWidth = Convert.ToInt32(sourceWidth * percentHeight); switch (options.Position) { case AnchorPosition.Left: case AnchorPosition.TopLeft: case AnchorPosition.BottomLeft: destinationX = 0; break; case AnchorPosition.Right: case AnchorPosition.TopRight: case AnchorPosition.BottomRight: destinationX = (int)(width - (sourceWidth * ratio)); break; default: destinationX = Convert.ToInt32((width - (sourceWidth * ratio)) / 2); break; } } else { ratio = percentWidth; destinationHeight = Convert.ToInt32(sourceHeight * percentWidth); switch (options.Position) { case AnchorPosition.Top: case AnchorPosition.TopLeft: case AnchorPosition.TopRight: destinationY = 0; break; case AnchorPosition.Bottom: case AnchorPosition.BottomLeft: case AnchorPosition.BottomRight: destinationY = (int)(height - (sourceHeight * ratio)); break; default: destinationY = (int)((height - (sourceHeight * ratio)) / 2); break; } } return(new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight)); }
/// <summary> /// Combines the given image together with the current one by blending their pixels. /// </summary> /// <param name="source">The image this method extends.</param> /// <param name="image">The image to blend with the currently processing image.</param> /// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam> /// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</param> /// <param name="rectangle"> /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter. /// </param> /// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns> public static Image <TColor, TPacked> Blend <TColor, TPacked>(this Image <TColor, TPacked> source, ImageBase <TColor, TPacked> image, int percent, Rectangle rectangle) where TColor : struct, IPackedPixel <TPacked> where TPacked : struct { return(source.Process(rectangle, new BlendProcessor <TColor, TPacked>(image, percent))); }
/// <summary> /// Combines the given image together with the current one by blending their pixels. /// </summary> /// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam> /// <param name="source">The image this method extends.</param> /// <param name="image">The image to blend with the currently processing image.</param> /// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</param> /// <returns>The <see cref="Image{TColor, TPacked}"/>.</returns> public static Image <TColor, TPacked> Blend <TColor, TPacked>(this Image <TColor, TPacked> source, ImageBase <TColor, TPacked> image, int percent = 50) where TColor : struct, IPackedPixel <TPacked> where TPacked : struct { return(Blend(source, image, percent, source.Bounds)); }