|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 2.7 KiB |
@ -1,149 +0,0 @@ |
|||||
|
|
||||
# Features |
|
||||
|
|
||||
### What works so far/ What is planned? |
|
||||
|
|
||||
We've achieved a lot so far and hope to do a lot more in the future. We're always looking for help so please pitch in! |
|
||||
|
|
||||
- **Encoding/decoding of image formats (plugable).** |
|
||||
- [x] Jpeg (Includes Subsampling. Progressive writing required) |
|
||||
- [x] Bmp (Read: 32bit, 24bit, 16 bit. Write: 32bit, 24bit just now) |
|
||||
- [x] Png (Read: Rgb, Rgba, Grayscale, Grayscale + alpha, Palette. Write: Rgb, Rgba, Grayscale, Grayscale + alpha, Palette) Supports interlaced decoding |
|
||||
- [x] Gif (Includes animated) |
|
||||
- [ ] Tiff (Help needed) |
|
||||
- **Metadata** |
|
||||
- [x] EXIF Read/Write (Jpeg just now) |
|
||||
- [ ] ICC (In Progress) |
|
||||
- **Quantizers (IQuantizer with alpha channel support, dithering, and thresholding)** |
|
||||
- [x] Octree |
|
||||
- [x] Xiaolin Wu |
|
||||
- [x] Palette |
|
||||
- **DIthering (Error diffusion and Ordered)** |
|
||||
- [x] Atkinson |
|
||||
- [x] Burks |
|
||||
- [x] FloydSteinburg |
|
||||
- [x] JarvisJudiceNinke |
|
||||
- [x] Sieera2 |
|
||||
- [x] Sierra3 |
|
||||
- [x] SerraLite |
|
||||
- [x] Bayer |
|
||||
- [x] Ordered |
|
||||
- **Basic color structs with implicit operators.** |
|
||||
- [x] Bgra32 |
|
||||
- [x] CIE Lab |
|
||||
- [x] CIE XYZ |
|
||||
- [x] CMYK |
|
||||
- [x] HSV |
|
||||
- [x] HSL |
|
||||
- [x] YCbCr |
|
||||
- **IPackedPixel representations of color models. Compatible with Microsoft XNA Game Studio and MonoGame IPackedVector\<TPacked\>.** |
|
||||
- [x] Alpha8 |
|
||||
- [x] Argb32 |
|
||||
- [x] Bgr565 |
|
||||
- [x] Bgra444 |
|
||||
- [x] Bgra565 |
|
||||
- [x] Byte4 |
|
||||
- [x] HalfSingle |
|
||||
- [x] HalfVector2 |
|
||||
- [x] HalfVector4 |
|
||||
- [x] NormalizedByte2 |
|
||||
- [x] NormalizedByte4 |
|
||||
- [x] NormalizedShort2 |
|
||||
- [x] NormalizedShort4 |
|
||||
- [x] Rg32 |
|
||||
- [x] Rgba1010102 |
|
||||
- [x] Rgba32 - 32bit color in RGBA order - Our default pixel format. |
|
||||
- [x] Rgba64 |
|
||||
- [x] RgbaVector |
|
||||
- [x] Short2 |
|
||||
- [x] Short4 |
|
||||
- **Basic shape primitives.** |
|
||||
- [x] Rectangle |
|
||||
- [x] Size |
|
||||
- [x] Point |
|
||||
- [x] Ellipse |
|
||||
- **Resampling algorithms. (Optional gamma correction, resize modes, Performance improvements?)** |
|
||||
- [x] Box |
|
||||
- [x] Bicubic |
|
||||
- [x] Lanczos2 |
|
||||
- [x] Lanczos3 |
|
||||
- [x] Lanczos5 |
|
||||
- [x] Lanczos8 |
|
||||
- [x] MitchelNetravali |
|
||||
- [x] Nearest Neighbour |
|
||||
- [x] Robidoux |
|
||||
- [x] Robidoux Sharp |
|
||||
- [x] Spline |
|
||||
- [x] Triangle |
|
||||
- [x] Welch |
|
||||
- **Padding** |
|
||||
- [x] Pad |
|
||||
- [x] ResizeMode.Pad |
|
||||
- [x] ResizeMode.BoxPad |
|
||||
- **Cropping** |
|
||||
- [x] Rectangular Crop |
|
||||
- [ ] Elliptical Crop |
|
||||
- [x] Entropy Crop |
|
||||
- [x] ResizeMode.Crop |
|
||||
- **Rotation/Skew** |
|
||||
- [x] Flip (90, 270, FlipType etc) |
|
||||
- [x] Rotate by angle and center point (Expandable canvas). |
|
||||
- [x] Skew by x/y angles and center point (Expandable canvas). |
|
||||
- **ColorMatrix operations (Uses Matrix4x4)** |
|
||||
- [x] BlackWhite |
|
||||
- [x] Grayscale BT709 |
|
||||
- [x] Grayscale BT601 |
|
||||
- [x] Hue |
|
||||
- [x] Saturation |
|
||||
- [x] Lomograph |
|
||||
- [x] Polaroid |
|
||||
- [x] Kodachrome |
|
||||
- [x] Sepia |
|
||||
- [x] Achromatomaly |
|
||||
- [x] Achromatopsia |
|
||||
- [x] Deuteranomaly |
|
||||
- [x] Deuteranopia |
|
||||
- [x] Protanomaly |
|
||||
- [x] Protanopia |
|
||||
- [x] Tritanomaly |
|
||||
- [x] Tritanopia |
|
||||
- **Edge Detection** |
|
||||
- [x] Kayyali |
|
||||
- [x] Kirsch |
|
||||
- [x] Laplacian3X3 |
|
||||
- [x] Laplacian5X5 |
|
||||
- [x] LaplacianOfGaussian |
|
||||
- [x] Prewitt |
|
||||
- [x] RobertsCross |
|
||||
- [x] Robinson |
|
||||
- [x] Scharr |
|
||||
- [x] Sobel |
|
||||
- **Blurring/Sharpening** |
|
||||
- [x] Gaussian blur |
|
||||
- [x] Gaussian sharpening |
|
||||
- [x] Box Blur |
|
||||
- **Filters** |
|
||||
- [x] Alpha |
|
||||
- [x] Contrast |
|
||||
- [x] Invert |
|
||||
- [x] BackgroundColor |
|
||||
- [x] Brightness |
|
||||
- [x] Pixelate |
|
||||
- [ ] Mask |
|
||||
- [x] Oil Painting |
|
||||
- [x] Vignette |
|
||||
- [x] Glow |
|
||||
- [x] Threshold |
|
||||
- **Drawing** |
|
||||
- [x] Image brush |
|
||||
- [x] Pattern brush |
|
||||
- [x] Solid brush |
|
||||
- [X] Hatch brush (Partial copy of System.Drawing brushes) |
|
||||
- [x] Pen (Solid, Dash, Custom) |
|
||||
- [x] Line drawing |
|
||||
- [x] Complex Polygons (Fill, draw) |
|
||||
- [x] DrawImage |
|
||||
- [ ] Gradient brush (Need help) |
|
||||
- **DrawingText** |
|
||||
- [ ] DrawString (In-progress. Single variant support just now, no italic,bold) |
|
||||
- Other stuff I haven't thought of. |
|
||||
@ -1,3 +0,0 @@ |
|||||
Title: About This Project |
|
||||
--- |
|
||||
This project is awesome! |
|
||||
@ -1,10 +1,9 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
// Copyright (c) Six Labors and contributors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
using System; |
|
||||
using SixLabors.Primitives; |
using SixLabors.Primitives; |
||||
|
|
||||
namespace SixLabors.ImageSharp.Drawing |
namespace SixLabors.ImageSharp.Primitives |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// Represents a region of an image.
|
/// Represents a region of an image.
|
||||
@ -1,12 +1,10 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
// Copyright (c) Six Labors and contributors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
using SixLabors.ImageSharp.Drawing.Brushes.Processors; |
|
||||
using SixLabors.ImageSharp.Drawing.Processors; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
using SixLabors.ImageSharp.PixelFormats; |
||||
using SixLabors.Primitives; |
using SixLabors.Primitives; |
||||
|
|
||||
namespace SixLabors.ImageSharp.Drawing.Brushes |
namespace SixLabors.ImageSharp.Processing.Drawing.Brushes |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// Brush represents a logical configuration of a brush which can be used to source pixel colors
|
/// Brush represents a logical configuration of a brush which can be used to source pixel colors
|
||||
@ -1,20 +1,21 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
// Copyright (c) Six Labors and contributors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
using SixLabors.ImageSharp.Drawing.Brushes; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using SixLabors.ImageSharp.Processing.Drawing.Brushes; |
||||
|
|
||||
namespace SixLabors.ImageSharp.Drawing.Pens |
namespace SixLabors.ImageSharp.Processing.Drawing.Pens |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// Common Pen styles
|
/// Contains a collection of common Pen styles
|
||||
/// </summary>
|
/// </summary>
|
||||
public static class Pens |
public static class Pens |
||||
{ |
{ |
||||
private static readonly float[] DashDotPattern = new[] { 3f, 1f, 1f, 1f }; |
private static readonly float[] DashDotPattern = { 3f, 1f, 1f, 1f }; |
||||
private static readonly float[] DashDotDotPattern = new[] { 3f, 1f, 1f, 1f, 1f, 1f }; |
private static readonly float[] DashDotDotPattern = { 3f, 1f, 1f, 1f, 1f, 1f }; |
||||
private static readonly float[] DottedPattern = new[] { 1f, 1f }; |
private static readonly float[] DottedPattern = { 1f, 1f }; |
||||
private static readonly float[] DashedPattern = new[] { 3f, 1f }; |
private static readonly float[] DashedPattern = { 3f, 1f }; |
||||
|
internal static readonly float[] EmptyPattern = new float[0]; |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// Create a solid pen with out any drawing patterns
|
/// Create a solid pen with out any drawing patterns
|
||||
@ -0,0 +1,155 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using SixLabors.ImageSharp.Advanced; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using SixLabors.ImageSharp.Processing.Processors; |
||||
|
using SixLabors.Primitives; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Processing.Drawing.Processors |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Combines two images together by blending the pixels.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
internal class DrawImageProcessor<TPixel> : ImageProcessor<TPixel> |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="image">The image to blend with the currently processing image.</param>
|
||||
|
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
|
||||
|
public DrawImageProcessor(Image<TPixel> image, float opacity) |
||||
|
: this(image, Point.Empty, opacity) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="image">The image to blend with the currently processing image.</param>
|
||||
|
/// <param name="options">
|
||||
|
/// The options containing the opacity of the image to blend and blending mode.
|
||||
|
/// Opacity must be between 0 and 1.
|
||||
|
/// </param>
|
||||
|
public DrawImageProcessor(Image<TPixel> image, GraphicsOptions options) |
||||
|
: this(image, Point.Empty, options) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="image">The image to blend with the currently processing image.</param>
|
||||
|
/// <param name="location">The location to draw the blended image.</param>
|
||||
|
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
|
||||
|
public DrawImageProcessor(Image<TPixel> image, Point location, float opacity) |
||||
|
: this(image, location, opacity, GraphicsOptions.Default.BlenderMode) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="image">The image to blend with the currently processing image.</param>
|
||||
|
/// <param name="location">The location to draw the blended image.</param>
|
||||
|
/// <param name="options">
|
||||
|
/// The options containing the opacity of the image to blend and blending mode.
|
||||
|
/// Opacity must be between 0 and 1.
|
||||
|
/// </param>
|
||||
|
public DrawImageProcessor(Image<TPixel> image, Point location, GraphicsOptions options) |
||||
|
: this(image, location, options.BlendPercentage, options.BlenderMode) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="image">The image to blend with the currently processing image.</param>
|
||||
|
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
|
||||
|
/// <param name="blenderMode">The blending mode to use when drawing the image.</param>
|
||||
|
public DrawImageProcessor(Image<TPixel> image, float opacity, PixelBlenderMode blenderMode) |
||||
|
: this(image, Point.Empty, opacity, blenderMode) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="image">The image to blend with the currently processing image.</param>
|
||||
|
/// <param name="location">The location to draw the blended image.</param>
|
||||
|
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
|
||||
|
/// <param name="blenderMode">The blending mode to use when drawing the image.</param>
|
||||
|
public DrawImageProcessor(Image<TPixel> image, Point location, float opacity, PixelBlenderMode blenderMode) |
||||
|
{ |
||||
|
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); |
||||
|
|
||||
|
this.Image = image; |
||||
|
this.Opacity = opacity; |
||||
|
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(blenderMode); |
||||
|
this.Location = location; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the image to blend
|
||||
|
/// </summary>
|
||||
|
public Image<TPixel> Image { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the opacity of the image to blend
|
||||
|
/// </summary>
|
||||
|
public float Opacity { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the pixel blender
|
||||
|
/// </summary>
|
||||
|
public PixelBlender<TPixel> Blender { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the location to draw the blended image
|
||||
|
/// </summary>
|
||||
|
public Point Location { get; } |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
||||
|
{ |
||||
|
Image<TPixel> targetImage = this.Image; |
||||
|
PixelBlender<TPixel> blender = this.Blender; |
||||
|
int locationY = this.Location.Y; |
||||
|
|
||||
|
// Align start/end positions.
|
||||
|
Rectangle bounds = targetImage.Bounds(); |
||||
|
|
||||
|
int minX = Math.Max(this.Location.X, sourceRectangle.X); |
||||
|
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); |
||||
|
int targetX = minX - this.Location.X; |
||||
|
|
||||
|
int minY = Math.Max(this.Location.Y, sourceRectangle.Y); |
||||
|
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); |
||||
|
|
||||
|
int width = maxX - minX; |
||||
|
|
||||
|
MemoryManager memoryManager = this.Image.GetConfiguration().MemoryManager; |
||||
|
|
||||
|
using (IBuffer<float> amount = memoryManager.Allocate<float>(width)) |
||||
|
{ |
||||
|
amount.Span.Fill(this.Opacity); |
||||
|
|
||||
|
Parallel.For( |
||||
|
minY, |
||||
|
maxY, |
||||
|
configuration.ParallelOptions, |
||||
|
y => |
||||
|
{ |
||||
|
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width); |
||||
|
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); |
||||
|
blender.Blend(memoryManager, background, background, foreground, amount.Span); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,96 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using SixLabors.ImageSharp.Advanced; |
|
||||
using SixLabors.ImageSharp.Helpers; |
|
||||
using SixLabors.ImageSharp.Memory; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
|
||||
using SixLabors.ImageSharp.Processing; |
|
||||
using SixLabors.Primitives; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Drawing.Processors |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Combines two images together by blending the pixels.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|
||||
internal class DrawImageProcessor<TPixel> : ImageProcessor<TPixel> |
|
||||
where TPixel : struct, IPixel<TPixel> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
|
|
||||
/// </summary>
|
|
||||
/// <param name="image">The image to blend with the currently processing image.</param>
|
|
||||
/// <param name="location">The location to draw the blended image.</param>
|
|
||||
/// <param name="options">The opacity of the image to blend. Between 0 and 1.</param>
|
|
||||
public DrawImageProcessor(Image<TPixel> image, Point location, GraphicsOptions options) |
|
||||
{ |
|
||||
Guard.MustBeBetweenOrEqualTo(options.BlendPercentage, 0, 1, nameof(options.BlendPercentage)); |
|
||||
|
|
||||
this.Image = image; |
|
||||
this.Opacity = options.BlendPercentage; |
|
||||
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options.BlenderMode); |
|
||||
this.Location = location; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the image to blend
|
|
||||
/// </summary>
|
|
||||
public Image<TPixel> Image { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the opacity of the image to blend
|
|
||||
/// </summary>
|
|
||||
public float Opacity { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the pixel blender
|
|
||||
/// </summary>
|
|
||||
public PixelBlender<TPixel> Blender { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the location to draw the blended image
|
|
||||
/// </summary>
|
|
||||
public Point Location { get; } |
|
||||
|
|
||||
/// <inheritdoc/>
|
|
||||
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
|
||||
{ |
|
||||
Image<TPixel> targetImage = this.Image; |
|
||||
PixelBlender<TPixel> blender = this.Blender; |
|
||||
int locationY = this.Location.Y; |
|
||||
|
|
||||
// Align start/end positions.
|
|
||||
Rectangle bounds = targetImage.Bounds(); |
|
||||
|
|
||||
int minX = Math.Max(this.Location.X, sourceRectangle.X); |
|
||||
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); |
|
||||
int targetX = minX - this.Location.X; |
|
||||
|
|
||||
int minY = Math.Max(this.Location.Y, sourceRectangle.Y); |
|
||||
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); |
|
||||
|
|
||||
int width = maxX - minX; |
|
||||
|
|
||||
MemoryManager memoryManager = this.Image.GetConfiguration().MemoryManager; |
|
||||
|
|
||||
using (IBuffer<float> amount = memoryManager.Allocate<float>(width)) |
|
||||
{ |
|
||||
amount.Span.Fill(this.Opacity); |
|
||||
|
|
||||
Parallel.For( |
|
||||
minY, |
|
||||
maxY, |
|
||||
configuration.ParallelOptions, |
|
||||
y => |
|
||||
{ |
|
||||
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width); |
|
||||
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); |
|
||||
blender.Blend(memoryManager, background, background, foreground, amount.Span); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,61 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.IO; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
using System.Text; |
|
||||
using SixLabors.ImageSharp.Advanced; |
|
||||
using SixLabors.ImageSharp.Formats; |
|
||||
using SixLabors.ImageSharp.PixelFormats; |
|
||||
using SixLabors.Primitives; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Helpers |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Extension methods over Image{TPixel}
|
|
||||
/// </summary>
|
|
||||
public static partial class ImageExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Gets the bounds of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The Pixel format.</typeparam>
|
|
||||
/// <param name="source">The source image</param>
|
|
||||
/// <returns>Returns the bounds of the image</returns>
|
|
||||
public static Rectangle Bounds<TPixel>(this Image<TPixel> source) |
|
||||
where TPixel : struct, IPixel<TPixel> |
|
||||
=> new Rectangle(0, 0, source.Width, source.Height); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the bounds of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The Pixel format.</typeparam>
|
|
||||
/// <param name="source">The source image</param>
|
|
||||
/// <returns>Returns the bounds of the image</returns>
|
|
||||
public static Rectangle Bounds<TPixel>(this ImageFrame<TPixel> source) |
|
||||
where TPixel : struct, IPixel<TPixel> |
|
||||
=> new Rectangle(0, 0, source.Width, source.Height); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the size of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The Pixel format.</typeparam>
|
|
||||
/// <param name="source">The source image</param>
|
|
||||
/// <returns>Returns the bounds of the image</returns>
|
|
||||
public static Size Size<TPixel>(this Image<TPixel> source) |
|
||||
where TPixel : struct, IPixel<TPixel> |
|
||||
=> new Size(source.Width, source.Height); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the size of the image.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TPixel">The Pixel format.</typeparam>
|
|
||||
/// <param name="source">The source image</param>
|
|
||||
/// <returns>Returns the bounds of the image</returns>
|
|
||||
public static Size Size<TPixel>(this ImageFrame<TPixel> source) |
|
||||
where TPixel : struct, IPixel<TPixel> |
|
||||
=> new Size(source.Width, source.Height); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,27 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using SixLabors.Primitives; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Extension methods that allow the addition of geometry calculating methods to the <see cref="IImageInfo"/> type
|
||||
|
/// </summary>
|
||||
|
public static class ImageInfoExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the bounds of the image.
|
||||
|
/// </summary>
|
||||
|
/// <param name="info">The image info</param>
|
||||
|
/// <returns>The <see cref="Size"/></returns>
|
||||
|
public static Size Size(this IImageInfo info) => new Size(info.Width, info.Height); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the bounds of the image.
|
||||
|
/// </summary>
|
||||
|
/// <param name="info">The image info</param>
|
||||
|
/// <returns>The <see cref="Rectangle"/></returns>
|
||||
|
public static Rectangle Bounds(this IImageInfo info) => new Rectangle(0, 0, info.Width, info.Height); |
||||
|
} |
||||
|
} |
||||
@ -1,173 +0,0 @@ |
|||||
// Copyright (c) Six Labors and contributors.
|
|
||||
// Licensed under the Apache License, Version 2.0.
|
|
||||
|
|
||||
using System; |
|
||||
using System.Diagnostics; |
|
||||
using System.Runtime.CompilerServices; |
|
||||
|
|
||||
namespace SixLabors.ImageSharp.Memory |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides fast access to 2D arrays.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="T">The type of elements in the array.</typeparam>
|
|
||||
internal struct Fast2DArray<T> |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// The 1D representation of the 2D array.
|
|
||||
/// </summary>
|
|
||||
public T[] Data; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the width of the 2D array.
|
|
||||
/// </summary>
|
|
||||
public int Width; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the height of the 2D array.
|
|
||||
/// </summary>
|
|
||||
public int Height; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the number of items in the 2D array
|
|
||||
/// </summary>
|
|
||||
public int Count; |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Fast2DArray{T}" /> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="length">The length of each dimension.</param>
|
|
||||
public Fast2DArray(int length) |
|
||||
: this(length, length) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Fast2DArray{T}" /> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="width">The width.</param>
|
|
||||
/// <param name="height">The height.</param>
|
|
||||
public Fast2DArray(int width, int height) |
|
||||
{ |
|
||||
this.Height = height; |
|
||||
this.Width = width; |
|
||||
|
|
||||
Guard.MustBeGreaterThan(width, 0, nameof(width)); |
|
||||
Guard.MustBeGreaterThan(height, 0, nameof(height)); |
|
||||
|
|
||||
this.Count = width * height; |
|
||||
this.Data = new T[this.Count]; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Initializes a new instance of the <see cref="Fast2DArray{T}"/> struct.
|
|
||||
/// </summary>
|
|
||||
/// <param name="data">The 2D array to provide access to.</param>
|
|
||||
public Fast2DArray(T[,] data) |
|
||||
{ |
|
||||
Guard.NotNull(data, nameof(data)); |
|
||||
this.Height = data.GetLength(0); |
|
||||
this.Width = data.GetLength(1); |
|
||||
|
|
||||
Guard.MustBeGreaterThan(this.Width, 0, nameof(this.Width)); |
|
||||
Guard.MustBeGreaterThan(this.Height, 0, nameof(this.Height)); |
|
||||
|
|
||||
this.Count = this.Width * this.Height; |
|
||||
this.Data = new T[this.Count]; |
|
||||
|
|
||||
for (int y = 0; y < this.Height; y++) |
|
||||
{ |
|
||||
for (int x = 0; x < this.Width; x++) |
|
||||
{ |
|
||||
this.Data[(y * this.Width) + x] = data[y, x]; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets or sets the item at the specified position.
|
|
||||
/// </summary>
|
|
||||
/// <param name="row">The row-coordinate of the item. Must be greater than or equal to zero and less than the height of the array.</param>
|
|
||||
/// <param name="column">The column-coordinate of the item. Must be greater than or equal to zero and less than the width of the array.</param>
|
|
||||
/// <returns>The <see typeparam="T"/> at the specified position.</returns>
|
|
||||
public T this[int row, int column] |
|
||||
{ |
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
get |
|
||||
{ |
|
||||
this.CheckCoordinates(row, column); |
|
||||
return this.Data[(row * this.Width) + column]; |
|
||||
} |
|
||||
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
set |
|
||||
{ |
|
||||
this.CheckCoordinates(row, column); |
|
||||
this.Data[(row * this.Width) + column] = value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Performs an implicit conversion from a 2D array to a <see cref="Fast2DArray{T}" />.
|
|
||||
/// </summary>
|
|
||||
/// <param name="data">The source array.</param>
|
|
||||
/// <returns>
|
|
||||
/// The <see cref="Fast2DArray{T}"/> representation on the source data.
|
|
||||
/// </returns>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public static implicit operator Fast2DArray<T>(T[,] data) |
|
||||
{ |
|
||||
return new Fast2DArray<T>(data); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets a <see cref="Span{T}"/> representing the row beginning from the the first item on that row.
|
|
||||
/// </summary>
|
|
||||
/// <param name="row">The y-coordinate of the row. Must be greater than or equal to zero and less than the height of the 2D array.</param>
|
|
||||
/// <returns>The <see cref="Span{T}"/></returns>
|
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
||||
public Span<T> GetRowSpan(int row) |
|
||||
{ |
|
||||
this.CheckCoordinates(row); |
|
||||
return new Span<T>(this.Data, row * this.Width, this.Width); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Checks the coordinates to ensure they are within bounds.
|
|
||||
/// </summary>
|
|
||||
/// <param name="row">The y-coordinate of the item. Must be greater than zero and smaller than the height of the array.</param>
|
|
||||
/// <param name="column">The x-coordinate of the item. Must be greater than zero and smaller than the width of the array.</param>
|
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
|
||||
/// Thrown if the coordinates are not within the bounds of the array.
|
|
||||
/// </exception>
|
|
||||
[Conditional("DEBUG")] |
|
||||
private void CheckCoordinates(int row, int column) |
|
||||
{ |
|
||||
if (row < 0 || row >= this.Height) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(nameof(row), row, $"{row} is outwith the array bounds."); |
|
||||
} |
|
||||
|
|
||||
if (column < 0 || column >= this.Width) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(nameof(column), column, $"{column} is outwith the array bounds."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Checks the coordinates to ensure they are within bounds.
|
|
||||
/// </summary>
|
|
||||
/// <param name="row">The y-coordinate of the item. Must be greater than zero and smaller than the height of the array.</param>
|
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
|
||||
/// Thrown if the coordinates are not within the bounds of the image.
|
|
||||
/// </exception>
|
|
||||
[Conditional("DEBUG")] |
|
||||
private void CheckCoordinates(int row) |
|
||||
{ |
|
||||
if (row < 0 || row >= this.Height) |
|
||||
{ |
|
||||
throw new ArgumentOutOfRangeException(nameof(row), row, $"{row} is outwith the array bounds."); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,215 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Diagnostics; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Primitives |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a dense matrix with arbitrary elements.
|
||||
|
/// Components that are adjacent in a column of the matrix are adjacent in the storage array.
|
||||
|
/// The components are said to be stored in column major order.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">The type of elements in the matrix.</typeparam>
|
||||
|
public readonly struct DenseMatrix<T> : IEquatable<DenseMatrix<T>> |
||||
|
where T : struct, IEquatable<T> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The 1D representation of the dense matrix.
|
||||
|
/// </summary>
|
||||
|
public readonly T[] Data; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the number of columns in the dense matrix.
|
||||
|
/// </summary>
|
||||
|
public readonly int Columns; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the number of rows in the dense matrix.
|
||||
|
/// </summary>
|
||||
|
public readonly int Rows; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the number of items in the array.
|
||||
|
/// </summary>
|
||||
|
public readonly int Count; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref=" DenseMatrix{T}" /> struct.
|
||||
|
/// </summary>
|
||||
|
/// <param name="length">The length of each side in the matrix.</param>
|
||||
|
public DenseMatrix(int length) |
||||
|
: this(length, length) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref=" DenseMatrix{T}" /> struct.
|
||||
|
/// </summary>
|
||||
|
/// <param name="columns">The number of columns.</param>
|
||||
|
/// <param name="rows">The number of rows.</param>
|
||||
|
public DenseMatrix(int columns, int rows) |
||||
|
{ |
||||
|
Guard.MustBeGreaterThan(columns, 0, nameof(columns)); |
||||
|
Guard.MustBeGreaterThan(rows, 0, nameof(rows)); |
||||
|
|
||||
|
this.Rows = rows; |
||||
|
this.Columns = columns; |
||||
|
this.Count = columns * rows; |
||||
|
this.Data = new T[this.Columns * this.Rows]; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref=" DenseMatrix{T}"/> struct.
|
||||
|
/// </summary>
|
||||
|
/// <param name="data">The 2D array to provide access to.</param>
|
||||
|
public DenseMatrix(T[,] data) |
||||
|
{ |
||||
|
Guard.NotNull(data, nameof(data)); |
||||
|
int rows = data.GetLength(0); |
||||
|
int columns = data.GetLength(1); |
||||
|
|
||||
|
Guard.MustBeGreaterThan(rows, 0, nameof(this.Rows)); |
||||
|
Guard.MustBeGreaterThan(columns, 0, nameof(this.Columns)); |
||||
|
|
||||
|
this.Rows = rows; |
||||
|
this.Columns = columns; |
||||
|
this.Count = this.Columns * this.Rows; |
||||
|
this.Data = new T[this.Columns * this.Rows]; |
||||
|
|
||||
|
for (int y = 0; y < this.Rows; y++) |
||||
|
{ |
||||
|
for (int x = 0; x < this.Columns; x++) |
||||
|
{ |
||||
|
ref T value = ref this[y, x]; |
||||
|
value = data[y, x]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the item at the specified position.
|
||||
|
/// </summary>
|
||||
|
/// <param name="row">The row-coordinate of the item. Must be greater than or equal to zero and less than the height of the array.</param>
|
||||
|
/// <param name="column">The column-coordinate of the item. Must be greater than or equal to zero and less than the width of the array.</param>
|
||||
|
/// <returns>The <see typeparam="T"/> at the specified position.</returns>
|
||||
|
public ref T this[int row, int column] |
||||
|
{ |
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
get |
||||
|
{ |
||||
|
this.CheckCoordinates(row, column); |
||||
|
return ref this.Data[(row * this.Columns) + column]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Performs an implicit conversion from a <see cref="T:T[,]" /> to a <see cref=" DenseMatrix{T}" />.
|
||||
|
/// </summary>
|
||||
|
/// <param name="data">The source array.</param>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="DenseMatrix{T}"/> representation on the source data.
|
||||
|
/// </returns>
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public static implicit operator DenseMatrix<T>(T[,] data) => new DenseMatrix<T>(data); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Performs an implicit conversion from a <see cref="DenseMatrix{T}"/> to a <see cref="T:T[,]" />.
|
||||
|
/// </summary>
|
||||
|
/// <param name="data">The source array.</param>
|
||||
|
/// <returns>
|
||||
|
/// The <see cref="T:T[,]"/> representation on the source data.
|
||||
|
/// </returns>
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
#pragma warning disable SA1008 // Opening parenthesis should be spaced correctly
|
||||
|
public static implicit operator T[,] (DenseMatrix<T> data) |
||||
|
#pragma warning restore SA1008 // Opening parenthesis should be spaced correctly
|
||||
|
{ |
||||
|
var result = new T[data.Rows, data.Columns]; |
||||
|
|
||||
|
for (int y = 0; y < data.Rows; y++) |
||||
|
{ |
||||
|
for (int x = 0; x < data.Columns; x++) |
||||
|
{ |
||||
|
ref T value = ref result[y, x]; |
||||
|
value = data[y, x]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Fills the matrix with the given value
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">The value to fill each item with</param>
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public void Fill(T value) |
||||
|
{ |
||||
|
for (int i = 0; i < this.Data.Length; i++) |
||||
|
{ |
||||
|
this.Data[i] = value; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Clears the matrix setting each value to the default value for the element type
|
||||
|
/// </summary>
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public void Clear() => Array.Clear(this.Data, 0, this.Data.Length); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Checks the coordinates to ensure they are within bounds.
|
||||
|
/// </summary>
|
||||
|
/// <param name="row">The y-coordinate of the item. Must be greater than zero and smaller than the height of the matrix.</param>
|
||||
|
/// <param name="column">The x-coordinate of the item. Must be greater than zero and smaller than the width of the matrix.</param>
|
||||
|
/// <exception cref="ArgumentOutOfRangeException">
|
||||
|
/// Thrown if the coordinates are not within the bounds of the array.
|
||||
|
/// </exception>
|
||||
|
[Conditional("DEBUG")] |
||||
|
private void CheckCoordinates(int row, int column) |
||||
|
{ |
||||
|
if (row < 0 || row >= this.Rows) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException(nameof(row), row, $"{row} is outwith the matrix bounds."); |
||||
|
} |
||||
|
|
||||
|
if (column < 0 || column >= this.Columns) |
||||
|
{ |
||||
|
throw new ArgumentOutOfRangeException(nameof(column), column, $"{column} is outwith the matrix bounds."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public bool Equals(DenseMatrix<T> other) |
||||
|
{ |
||||
|
if (this.Columns != other.Columns) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (this.Rows != other.Rows) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
for (int i = 0; i < this.Data.Length; i++) |
||||
|
{ |
||||
|
if (!this.Data[i].Equals(other.Data[i])) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override bool Equals(object obj) => obj is DenseMatrix<T> matrix && this.Equals(matrix); |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public override int GetHashCode() => this.Data.GetHashCode(); |
||||
|
} |
||||
|
} |
||||