/// <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> /// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></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, TPacked>(ImageBase <TColor, TPacked> bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) where TColor : struct, IPackedPixel <TPacked> where TPacked : struct, IEquatable <TPacked> { const float Epsilon = .00001f; int width = bitmap.Width; int height = bitmap.Height; Point topLeft = default(Point); Point bottomRight = default(Point); Func <PixelAccessor <TColor, TPacked>, int, int, float, bool> delegateFunc; // Determine which channel to check against switch (channel) { case RgbaComponent.R: delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().X - b) > Epsilon; break; case RgbaComponent.G: delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Y - b) > Epsilon; break; case RgbaComponent.B: delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Z - b) > Epsilon; break; default: delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().W - b) > Epsilon; break; } Func <PixelAccessor <TColor, TPacked>, 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, TPacked>, 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, TPacked>, 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, TPacked>, 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, TPacked> 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 pixels to another <see cref="PixelAccessor{TColor}"/> of the same size. /// </summary> /// <param name="target">The target pixel buffer accessor.</param> internal void CopyTo(PixelAccessor <TColor> target) { uint byteCount = (uint)(this.Width * this.Height * Unsafe.SizeOf <TColor>()); Unsafe.CopyBlock(target.pixelsBase, this.pixelsBase, byteCount); }
/// <summary> /// Copies an entire image. /// </summary> /// <param name="target">The target pixel buffer accessor.</param> public void CopyImage(PixelAccessor <TColor, TPacked> target) { this.CopyBlock(0, 0, target, 0, 0, target.Width * target.Height); }
/// <summary> /// Copies the pixels to another <see cref="PixelAccessor{TPixel}"/> of the same size. /// </summary> /// <param name="target">The target pixel buffer accessor.</param> internal void CopyTo(PixelAccessor <TPixel> target) { SpanHelper.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span); }