/// <summary> /// Initializes a new instance of the <see cref="ImageBase{TColor, TPacked}"/> class. /// </summary> /// <param name="other"> /// The other <see cref="ImageBase{TColor, TPacked}"/> to create this instance from. /// </param> /// <exception cref="System.ArgumentNullException"> /// Thrown if the given <see cref="ImageBase{TColor, TPacked}"/> is null. /// </exception> protected ImageBase(ImageBase <TColor, TPacked> other) { Guard.NotNull(other, nameof(other), "Other image cannot be null."); this.Width = other.Width; this.Height = other.Height; this.CopyProperties(other); // Copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here. this.pixelBuffer = new TColor[this.Width * this.Height]; using (PixelAccessor <TColor, TPacked> sourcePixels = other.Lock()) using (PixelAccessor <TColor, TPacked> target = this.Lock()) { sourcePixels.CopyImage(target); } }
/// <summary> /// Initializes a new instance of the <see cref="ImageBase{TColor}"/> class. /// </summary> /// <param name="other"> /// The other <see cref="ImageBase{TColor}"/> to create this instance from. /// </param> /// <exception cref="System.ArgumentNullException"> /// Thrown if the given <see cref="ImageBase{TColor}"/> is null. /// </exception> protected ImageBase(ImageBase <TColor> other) { Guard.NotNull(other, nameof(other), "Other image cannot be null."); this.Width = other.Width; this.Height = other.Height; this.CopyProperties(other); // Rent then copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here. this.RentPixels(); using (PixelAccessor <TColor> sourcePixels = other.Lock()) using (PixelAccessor <TColor> target = this.Lock()) { // Check we can do this without crashing sourcePixels.CopyTo(target); } }
/// <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)); }