Browse Source

Merge remote-tracking branch 'origin/tocsoft/mutate-api' into antonfirsov/qa-lab

# Conflicts:
#	tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs
#	tests/ImageSharp.Tests/Processing/Binarization/DitherTest.cs
#	tests/ImageSharp.Tests/Processing/ColorMatrix/BlackWhiteTest.cs
#	tests/ImageSharp.Tests/Processing/ColorMatrix/ColorBlindnessTest.cs
#	tests/ImageSharp.Tests/Processing/ColorMatrix/HueTest.cs
#	tests/ImageSharp.Tests/Processing/ColorMatrix/KodachromeTest.cs
#	tests/ImageSharp.Tests/Processing/ColorMatrix/LomographTest.cs
#	tests/ImageSharp.Tests/Processing/ColorMatrix/PolaroidTest.cs
#	tests/ImageSharp.Tests/Processing/ColorMatrix/SaturationTest.cs
#	tests/ImageSharp.Tests/Processing/ColorMatrix/SepiaTest.cs
#	tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs
#	tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs
#	tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs
#	tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs
#	tests/ImageSharp.Tests/Processing/Effects/AlphaTest.cs
#	tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs
#	tests/ImageSharp.Tests/Processing/Effects/BrightnessTest.cs
#	tests/ImageSharp.Tests/Processing/Effects/ContrastTest.cs
#	tests/ImageSharp.Tests/Processing/Effects/InvertTest.cs
#	tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs
#	tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs
#	tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs
#	tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs
#	tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs
#	tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs
#	tests/ImageSharp.Tests/Processing/Transforms/EntropyCropTest.cs
#	tests/ImageSharp.Tests/Processing/Transforms/FlipTests.cs
#	tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs
#	tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs
#	tests/ImageSharp.Tests/Processing/Transforms/RotateFlipTests.cs
#	tests/ImageSharp.Tests/Processing/Transforms/RotateTests.cs
#	tests/ImageSharp.Tests/Processing/Transforms/SkewTest.cs
#	tests/ImageSharp.Tests/TestFile.cs
pull/298/head
Anton Firszov 9 years ago
parent
commit
5fb4461746
  1. 72
      samples/AvatarWithRoundedCorner/Program.cs
  2. 14
      src/ImageSharp.Drawing/DrawImage.cs
  3. 18
      src/ImageSharp.Drawing/FillRegion.cs
  4. 12
      src/ImageSharp.Drawing/Paths/DrawBeziers.cs
  5. 12
      src/ImageSharp.Drawing/Paths/DrawLines.cs
  6. 12
      src/ImageSharp.Drawing/Paths/DrawPath.cs
  7. 12
      src/ImageSharp.Drawing/Paths/DrawPathCollection.cs
  8. 12
      src/ImageSharp.Drawing/Paths/DrawPolygon.cs
  9. 12
      src/ImageSharp.Drawing/Paths/DrawRectangle.cs
  10. 8
      src/ImageSharp.Drawing/Paths/FillPathBuilder.cs
  11. 8
      src/ImageSharp.Drawing/Paths/FillPathCollection.cs
  12. 8
      src/ImageSharp.Drawing/Paths/FillPaths.cs
  13. 8
      src/ImageSharp.Drawing/Paths/FillPolygon.cs
  14. 8
      src/ImageSharp.Drawing/Paths/FillRectangle.cs
  15. 6
      src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
  16. 21
      src/ImageSharp.Drawing/Text/DrawText.Path.cs
  17. 21
      src/ImageSharp.Drawing/Text/DrawText.cs
  18. 9
      src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs
  19. 107
      src/ImageSharp/ApplyProcessors.cs
  20. 7
      src/ImageSharp/Configuration.cs
  21. 78
      src/ImageSharp/DefaultInternalImageProcessorContext.cs
  22. 19
      src/ImageSharp/Formats/Bmp/ImageExtensions.cs
  23. 21
      src/ImageSharp/Formats/Gif/ImageExtensions.cs
  24. 21
      src/ImageSharp/Formats/Jpeg/ImageExtensions.cs
  25. 21
      src/ImageSharp/Formats/Png/ImageExtensions.cs
  26. 38
      src/ImageSharp/IImageProcessingContextFactory.cs
  27. 48
      src/ImageSharp/IImageProcessingContext{TPixel}.cs
  28. 34
      src/ImageSharp/Image/ICloningImageProcessor.cs
  29. 10
      src/ImageSharp/Image/IImageBase.cs
  30. 2
      src/ImageSharp/Image/IImageProcessor.cs
  31. 51
      src/ImageSharp/Image/ImageBase{TPixel}.cs
  32. 153
      src/ImageSharp/Image/ImageExtensions.cs
  33. 63
      src/ImageSharp/Image/ImageFrame{TPixel}.cs
  34. 32
      src/ImageSharp/Image/ImageProcessingExtensions.cs
  35. 212
      src/ImageSharp/Image/Image{TPixel}.cs
  36. 9
      src/ImageSharp/MetaData/ImageFrameMetaData.cs
  37. 9
      src/ImageSharp/MetaData/ImageMetaData.cs
  38. 131
      src/ImageSharp/Numerics/ValueSize.cs
  39. 9
      src/ImageSharp/PixelFormats/PackedPixelConverterHelper.cs
  40. 7
      src/ImageSharp/Processing/Binarization/BinaryThreshold.cs
  41. 45
      src/ImageSharp/Processing/Binarization/Dither.cs
  42. 7
      src/ImageSharp/Processing/ColorMatrix/BlackWhite.cs
  43. 48
      src/ImageSharp/Processing/ColorMatrix/ColorBlindness.cs
  44. 20
      src/ImageSharp/Processing/ColorMatrix/Grayscale.cs
  45. 7
      src/ImageSharp/Processing/ColorMatrix/Hue.cs
  46. 7
      src/ImageSharp/Processing/ColorMatrix/Kodachrome.cs
  47. 13
      src/ImageSharp/Processing/ColorMatrix/Lomograph.cs
  48. 11
      src/ImageSharp/Processing/ColorMatrix/Polaroid.cs
  49. 7
      src/ImageSharp/Processing/ColorMatrix/Saturation.cs
  50. 13
      src/ImageSharp/Processing/ColorMatrix/Sepia.cs
  51. 23
      src/ImageSharp/Processing/Convolution/BoxBlur.cs
  52. 91
      src/ImageSharp/Processing/Convolution/DetectEdges.cs
  53. 23
      src/ImageSharp/Processing/Convolution/GaussianBlur.cs
  54. 23
      src/ImageSharp/Processing/Convolution/GaussianSharpen.cs
  55. 30
      src/ImageSharp/Processing/Delegate.cs
  56. 13
      src/ImageSharp/Processing/Effects/Alpha.cs
  57. 17
      src/ImageSharp/Processing/Effects/BackgroundColor.cs
  58. 15
      src/ImageSharp/Processing/Effects/Brightness.cs
  59. 13
      src/ImageSharp/Processing/Effects/Contrast.cs
  60. 13
      src/ImageSharp/Processing/Effects/Invert.cs
  61. 26
      src/ImageSharp/Processing/Effects/OilPainting.cs
  62. 28
      src/ImageSharp/Processing/Effects/Pixelate.cs
  63. 79
      src/ImageSharp/Processing/Overlays/Glow.cs
  64. 54
      src/ImageSharp/Processing/Overlays/Vignette.cs
  65. 166
      src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
  66. 2
      src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs
  67. 6
      src/ImageSharp/Processing/Processors/ColorMatrix/SaturationProcessor.cs
  68. 6
      src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
  69. 2
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
  70. 4
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
  71. 5
      src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs
  72. 5
      src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs
  73. 48
      src/ImageSharp/Processing/Processors/DelegateProcessor.cs
  74. 5
      src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs
  75. 5
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs
  76. 13
      src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs
  77. 66
      src/ImageSharp/Processing/Processors/ImageProcessor.cs
  78. 16
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
  79. 33
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
  80. 112
      src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs
  81. 8
      src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs
  82. 20
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
  83. 180
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  84. 3
      src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
  85. 3
      src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs
  86. 73
      src/ImageSharp/Processing/Transforms/AutoOrient.cs
  87. 15
      src/ImageSharp/Processing/Transforms/Crop.cs
  88. 9
      src/ImageSharp/Processing/Transforms/EntropyCrop.cs
  89. 9
      src/ImageSharp/Processing/Transforms/Flip.cs
  90. 2
      src/ImageSharp/Processing/Transforms/Pad.cs
  91. 123
      src/ImageSharp/Processing/Transforms/Resize.cs
  92. 17
      src/ImageSharp/Processing/Transforms/Rotate.cs
  93. 2
      src/ImageSharp/Processing/Transforms/RotateFlip.cs
  94. 11
      src/ImageSharp/Processing/Transforms/Skew.cs
  95. 45
      src/ImageSharp/Quantizers/Quantize.cs
  96. 2
      src/ImageSharp/Quantizers/Quantizer{TPixel}.cs
  97. 4
      src/Shared/AssemblyInfo.Common.cs
  98. 4
      tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs
  99. 4
      tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs
  100. 4
      tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs

72
samples/AvatarWithRoundedCorner/Program.cs

@ -8,62 +8,74 @@ namespace AvatarWithRoundedCorner
using SixLabors.Primitives;
using SixLabors.Shapes;
class Program
static class Program
{
static void Main(string[] args)
{
System.IO.Directory.CreateDirectory("output");
using (var img = Image.Load("fb.jpg"))
{
// as generate returns a new IImage make sure we dispose of it
using (Image<Rgba32> dest = img.Clone(x => x.ConvertToAvatar(new Size(200, 200), 20)))
{
dest.Save("output/fb.png");
}
GenerateAvatar("fb.jpg", "output/fb.png", new Size(200, 200), 20);
GenerateAvatar("fb.jpg", "output/fb-round.png", new Size(200, 200), 100);
GenerateAvatar("fb.jpg", "output/fb-rounder.png", new Size(200, 200), 150);
using (Image<Rgba32> destRound = img.Clone(x => x.ConvertToAvatar(new Size(200, 200), 100)))
{
destRound.Save("output/fb-round.png");
}
using (Image<Rgba32> destRound = img.Clone(x => x.ConvertToAvatar(new Size(200, 200), 150)))
{
destRound.Save("output/fb-rounder.png");
}
// the original `img` object has not been altered at all.
}
}
private static void GenerateAvatar(string source, string destination, Size size, float cornerRadius)
// lets create our custom image mutating pipeline
private static IImageProcessingContext<Rgba32> ConvertToAvatar(this IImageProcessingContext<Rgba32> operations, Size size, float cornerRadius)
{
using (var image = Image.Load(source))
return operations.Resize(new ImageSharp.Processing.ResizeOptions
{
image.Resize(new ImageSharp.Processing.ResizeOptions
{
Size = size,
Mode = ImageSharp.Processing.ResizeMode.Crop
});
ApplyRoundedCourners(image, cornerRadius);
image.Save(destination);
}
Size = size,
Mode = ImageSharp.Processing.ResizeMode.Crop
}).Apply(i => ApplyRoundedCorners(i, cornerRadius));
}
public static void ApplyRoundedCourners(Image<Rgba32> img, float cornerRadius)
// the combination of `IImageOperations.Run()` + this could be replaced with an `IImageProcessor`
public static void ApplyRoundedCorners(Image<Rgba32> img, float cornerRadius)
{
var corners = BuildCorners(img.Width, img.Height, cornerRadius);
// now we have our corners time to draw them
img.Fill(Rgba32.Transparent, corners, new GraphicsOptions(true)
IPathCollection corners = BuildCorners(img.Width, img.Height, cornerRadius);
// mutating in here as we already have a cloned original
img.Mutate(x => x.Fill(Rgba32.Transparent, corners, new GraphicsOptions(true)
{
BlenderMode = ImageSharp.PixelFormats.PixelBlenderMode.Src // enforces that any part of this shape that has color is punched out of the background
});
}));
}
public static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius)
public static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius)
{
// first create a square
var rect = new SixLabors.Shapes.RectangularePolygon(-0.5f, -0.5f, cornerRadius, cornerRadius);
var rect = new RectangularePolygon(-0.5f, -0.5f, cornerRadius, cornerRadius);
// then cut out of the square a circle so we are left with a corner
var cornerToptLeft = rect.Clip(new SixLabors.Shapes.EllipsePolygon(cornerRadius-0.5f, cornerRadius - 0.5f, cornerRadius));
IPath cornerToptLeft = rect.Clip(new EllipsePolygon(cornerRadius - 0.5f, cornerRadius - 0.5f, cornerRadius));
// corner is now a corner shape positions top left
//lets make 3 more positioned correctly, we cando that by translating the orgional artound the center of the image
var center = new Vector2(imageWidth / 2, imageHeight / 2);
var angle = Math.PI / 2f;
//lets make 3 more positioned correctly, we can do that by translating the orgional artound the center of the image
var center = new Vector2(imageWidth / 2F, imageHeight / 2F);
float rightPos = imageWidth - cornerToptLeft.Bounds.Width +1;
float rightPos = imageWidth - cornerToptLeft.Bounds.Width + 1;
float bottomPos = imageHeight - cornerToptLeft.Bounds.Height + 1;
// move it across the widthof the image - the width of the shape
var cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0);
var cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos);
var cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos);
IPath cornerTopRight = cornerToptLeft.RotateDegree(90).Translate(rightPos, 0);
IPath cornerBottomLeft = cornerToptLeft.RotateDegree(-90).Translate(0, bottomPos);
IPath cornerBottomRight = cornerToptLeft.RotateDegree(180).Translate(rightPos, bottomPos);
return new PathCollection(cornerToptLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight);
}

14
src/ImageSharp.Drawing/DrawImage.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <param name="location">The location to draw the blended image.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawImage<TPixel>(this Image<TPixel> source, Image<TPixel> image, Size size, Point location, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Size size, Point location, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
if (size == default(Size))
@ -37,7 +37,7 @@ namespace ImageSharp
location = Point.Empty;
}
source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, size, location, options), source.Bounds);
source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, size, location, options));
return source;
}
@ -49,7 +49,7 @@ namespace ImageSharp
/// <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 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Blend<TPixel>(this Image<TPixel> source, Image<TPixel> image, float percent)
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float percent)
where TPixel : struct, IPixel<TPixel>
{
GraphicsOptions options = GraphicsOptions.Default;
@ -66,7 +66,7 @@ namespace ImageSharp
/// <param name="blender">The blending mode.</param>
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Blend<TPixel>(this Image<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float percent)
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float percent)
where TPixel : struct, IPixel<TPixel>
{
GraphicsOptions options = GraphicsOptions.Default;
@ -83,7 +83,7 @@ namespace ImageSharp
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="options">The options, including the blending type and belnding amount.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Blend<TPixel>(this Image<TPixel> source, Image<TPixel> image, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return DrawImage(source, image, default(Size), default(Point), options);
@ -99,7 +99,7 @@ namespace ImageSharp
/// <param name="size">The size to draw the blended image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawImage<TPixel>(this Image<TPixel> source, Image<TPixel> image, float percent, Size size, Point location)
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float percent, Size size, Point location)
where TPixel : struct, IPixel<TPixel>
{
GraphicsOptions options = GraphicsOptions.Default;
@ -118,7 +118,7 @@ namespace ImageSharp
/// <param name="size">The size to draw the blended image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawImage<TPixel>(this Image<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float percent, Size size, Point location)
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float percent, Size size, Point location)
where TPixel : struct, IPixel<TPixel>
{
GraphicsOptions options = GraphicsOptions.Default;

18
src/ImageSharp.Drawing/FillRegion.cs

@ -23,10 +23,10 @@ namespace ImageSharp
/// <param name="brush">The details how to fill the region of interest.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Apply(new FillProcessor<TPixel>(brush, options));
return source.ApplyProcessor(new FillProcessor<TPixel>(brush, options));
}
/// <summary>
@ -36,7 +36,7 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The details how to fill the region of interest.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, GraphicsOptions.Default);
@ -49,7 +49,7 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color));
@ -64,10 +64,10 @@ namespace ImageSharp
/// <param name="region">The region.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, Region region, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, Region region, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Apply(new FillRegionProcessor<TPixel>(brush, region, options));
return source.ApplyProcessor(new FillRegionProcessor<TPixel>(brush, region, options));
}
/// <summary>
@ -78,7 +78,7 @@ namespace ImageSharp
/// <param name="brush">The brush.</param>
/// <param name="region">The region.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, Region region)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, Region region)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, region, GraphicsOptions.Default);
@ -93,7 +93,7 @@ namespace ImageSharp
/// <param name="region">The region.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, Region region, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Region region, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), region, options);
@ -107,7 +107,7 @@ namespace ImageSharp
/// <param name="color">The color.</param>
/// <param name="region">The region.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, Region region)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Region region)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), region);

12
src/ImageSharp.Drawing/Paths/DrawBeziers.cs

@ -28,7 +28,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawBeziers<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), new Path(new CubicBezierLineSegment(points)), options);
@ -43,7 +43,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawBeziers<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), new Path(new CubicBezierLineSegment(points)));
@ -58,7 +58,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawBeziers<TPixel>(this Image<TPixel> source, TPixel color, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawBeziers(new SolidBrush<TPixel>(color), thickness, points);
@ -74,7 +74,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawBeziers<TPixel>(this Image<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawBeziers(new SolidBrush<TPixel>(color), thickness, points, options);
@ -89,7 +89,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawBeziers<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, new Path(new CubicBezierLineSegment(points)), options);
@ -103,7 +103,7 @@ namespace ImageSharp
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawBeziers<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, PointF[] points)
public static IImageProcessingContext<TPixel> DrawBeziers<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, new Path(new CubicBezierLineSegment(points)));

12
src/ImageSharp.Drawing/Paths/DrawLines.cs

@ -28,7 +28,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawLines<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), new Path(new LinearLineSegment(points)), options);
@ -43,7 +43,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawLines<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), new Path(new LinearLineSegment(points)));
@ -58,7 +58,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawLines<TPixel>(this Image<TPixel> source, TPixel color, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawLines(new SolidBrush<TPixel>(color), thickness, points);
@ -74,7 +74,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> DrawLines<TPixel>(this Image<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawLines(new SolidBrush<TPixel>(color), thickness, points, options);
@ -89,7 +89,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawLines<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, new Path(new LinearLineSegment(points)), options);
@ -103,7 +103,7 @@ namespace ImageSharp
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawLines<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, PointF[] points)
public static IImageProcessingContext<TPixel> DrawLines<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, new Path(new LinearLineSegment(points)));

12
src/ImageSharp.Drawing/Paths/DrawPath.cs

@ -25,7 +25,7 @@ namespace ImageSharp
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, IPath path, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(pen.StrokeFill, new ShapePath(path, pen), options);
@ -39,7 +39,7 @@ namespace ImageSharp
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, IPath path)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, path, GraphicsOptions.Default);
@ -55,7 +55,7 @@ namespace ImageSharp
/// <param name="path">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, IPath path, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), path, options);
@ -70,7 +70,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, IPath path)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), path);
@ -86,7 +86,7 @@ namespace ImageSharp
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, TPixel color, float thickness, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, IPath path, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new SolidBrush<TPixel>(color), thickness, path, options);
@ -101,7 +101,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, TPixel color, float thickness, IPath path)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new SolidBrush<TPixel>(color), thickness, path);

12
src/ImageSharp.Drawing/Paths/DrawPathCollection.cs

@ -25,7 +25,7 @@ namespace ImageSharp
/// <param name="paths">The paths.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, IPathCollection paths, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
foreach (IPath path in paths)
@ -44,7 +44,7 @@ namespace ImageSharp
/// <param name="pen">The pen.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, IPathCollection paths)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, paths, GraphicsOptions.Default);
@ -60,7 +60,7 @@ namespace ImageSharp
/// <param name="paths">The shapes.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, IPathCollection paths, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), paths, options);
@ -75,7 +75,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, IPathCollection paths)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), paths);
@ -91,7 +91,7 @@ namespace ImageSharp
/// <param name="paths">The paths.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, TPixel color, float thickness, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, IPathCollection paths, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new SolidBrush<TPixel>(color), thickness, paths, options);
@ -106,7 +106,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, TPixel color, float thickness, IPathCollection paths)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new SolidBrush<TPixel>(color), thickness, paths);

12
src/ImageSharp.Drawing/Paths/DrawPolygon.cs

@ -28,7 +28,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawPolygon<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), new Polygon(new LinearLineSegment(points)), options);
@ -43,7 +43,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawPolygon<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), new Polygon(new LinearLineSegment(points)));
@ -58,7 +58,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawPolygon<TPixel>(this Image<TPixel> source, TPixel color, float thickness, PointF[] points)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawPolygon(new SolidBrush<TPixel>(color), thickness, points);
@ -74,7 +74,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawPolygon<TPixel>(this Image<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawPolygon(new SolidBrush<TPixel>(color), thickness, points, options);
@ -88,7 +88,7 @@ namespace ImageSharp
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawPolygon<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, PointF[] points)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, new Polygon(new LinearLineSegment(points)), GraphicsOptions.Default);
@ -103,7 +103,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DrawPolygon<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, new Polygon(new LinearLineSegment(points)), options);

12
src/ImageSharp.Drawing/Paths/DrawRectangle.cs

@ -25,7 +25,7 @@ namespace ImageSharp
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, RectangleF shape, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, new SixLabors.Shapes.RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height), options);
@ -39,7 +39,7 @@ namespace ImageSharp
/// <param name="pen">The pen.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IPen<TPixel> pen, RectangleF shape)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IPen<TPixel> pen, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(pen, shape, GraphicsOptions.Default);
@ -55,7 +55,7 @@ namespace ImageSharp
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, RectangleF shape, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), shape, options);
@ -70,7 +70,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, float thickness, RectangleF shape)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, float thickness, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new Pen<TPixel>(brush, thickness), shape);
@ -86,7 +86,7 @@ namespace ImageSharp
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, TPixel color, float thickness, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, RectangleF shape, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new SolidBrush<TPixel>(color), thickness, shape, options);
@ -101,7 +101,7 @@ namespace ImageSharp
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Draw<TPixel>(this Image<TPixel> source, TPixel color, float thickness, RectangleF shape)
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float thickness, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
{
return source.Draw(new SolidBrush<TPixel>(color), thickness, shape);

8
src/ImageSharp.Drawing/Paths/FillPathBuilder.cs

@ -25,7 +25,7 @@ namespace ImageSharp
/// <param name="path">The shape.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, Action<PathBuilder> path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, Action<PathBuilder> path, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
var pb = new PathBuilder();
@ -42,7 +42,7 @@ namespace ImageSharp
/// <param name="brush">The brush.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, Action<PathBuilder> path)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, Action<PathBuilder> path)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, path, GraphicsOptions.Default);
@ -57,7 +57,7 @@ namespace ImageSharp
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, Action<PathBuilder> path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Action<PathBuilder> path, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), path, options);
@ -71,7 +71,7 @@ namespace ImageSharp
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, Action<PathBuilder> path)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Action<PathBuilder> path)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), path);

8
src/ImageSharp.Drawing/Paths/FillPathCollection.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <param name="paths">The shapes.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, IPathCollection paths, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
foreach (IPath s in paths)
@ -43,7 +43,7 @@ namespace ImageSharp
/// <param name="brush">The brush.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, IPathCollection paths)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, paths, GraphicsOptions.Default);
@ -58,7 +58,7 @@ namespace ImageSharp
/// <param name="paths">The paths.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, IPathCollection paths, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, IPathCollection paths, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), paths, options);
@ -72,7 +72,7 @@ namespace ImageSharp
/// <param name="color">The color.</param>
/// <param name="paths">The paths.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, IPathCollection paths)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, IPathCollection paths)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), paths);

8
src/ImageSharp.Drawing/Paths/FillPaths.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <param name="path">The shape.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, IPath path, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, new ShapeRegion(path), options);
@ -38,7 +38,7 @@ namespace ImageSharp
/// <param name="brush">The brush.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, IPath path)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, new ShapeRegion(path), GraphicsOptions.Default);
@ -53,7 +53,7 @@ namespace ImageSharp
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, IPath path, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, IPath path, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), path, options);
@ -67,7 +67,7 @@ namespace ImageSharp
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, IPath path)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), path);

8
src/ImageSharp.Drawing/Paths/FillPolygon.cs

@ -27,7 +27,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> FillPolygon<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, new Polygon(new LinearLineSegment(points)), options);
@ -41,7 +41,7 @@ namespace ImageSharp
/// <param name="brush">The brush.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> FillPolygon<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, PointF[] points)
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, new Polygon(new LinearLineSegment(points)));
@ -56,7 +56,7 @@ namespace ImageSharp
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> FillPolygon<TPixel>(this Image<TPixel> source, TPixel color, PointF[] points, GraphicsOptions options)
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, PointF[] points, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), new Polygon(new LinearLineSegment(points)), options);
@ -70,7 +70,7 @@ namespace ImageSharp
/// <param name="color">The color.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> FillPolygon<TPixel>(this Image<TPixel> source, TPixel color, PointF[] points)
public static IImageProcessingContext<TPixel> FillPolygon<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, PointF[] points)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), new Polygon(new LinearLineSegment(points)));

8
src/ImageSharp.Drawing/Paths/FillRectangle.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, RectangleF shape, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, new SixLabors.Shapes.RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height), options);
@ -38,7 +38,7 @@ namespace ImageSharp
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, IBrush<TPixel> brush, RectangleF shape)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(brush, new SixLabors.Shapes.RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height));
@ -53,7 +53,7 @@ namespace ImageSharp
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, RectangleF shape, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, RectangleF shape, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), shape, options);
@ -67,7 +67,7 @@ namespace ImageSharp
/// <param name="color">The color.</param>
/// <param name="shape">The shape.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Fill<TPixel>(this Image<TPixel> source, TPixel color, RectangleF shape)
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, RectangleF shape)
where TPixel : struct, IPixel<TPixel>
{
return source.Fill(new SolidBrush<TPixel>(color), shape);

6
src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs

@ -68,13 +68,13 @@ namespace ImageSharp.Drawing.Processors
try
{
if (targetImage.Bounds.Size != this.Size)
if (targetImage.Size() != this.Size)
{
targetImage = disposableImage = new Image<TPixel>(this.Image).Resize(this.Size.Width, this.Size.Height);
targetImage = disposableImage = this.Image.Clone(x => x.Resize(this.Size.Width, this.Size.Height));
}
// Align start/end positions.
Rectangle bounds = this.Image.Bounds;
Rectangle bounds = this.Image.Bounds();
int minX = Math.Max(this.Location.X, sourceRectangle.X);
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width);
maxX = Math.Min(this.Location.X + this.Size.Width, maxX);

21
src/ImageSharp.Drawing/Text/DrawText.Path.cs

@ -31,7 +31,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, TPixel color, IPath path)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, TPixel color, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, color, path, TextGraphicsOptions.Default);
@ -50,7 +50,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, TPixel color, IPath path, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, TPixel color, IPath path, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, Brushes.Solid(color), null, path, options);
@ -68,7 +68,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPath path)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, brush, path, TextGraphicsOptions.Default);
@ -87,7 +87,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPath path, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPath path, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, brush, null, path, options);
@ -105,7 +105,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IPen<TPixel> pen, IPath path)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IPen<TPixel> pen, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, pen, path, TextGraphicsOptions.Default);
@ -124,7 +124,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IPen<TPixel> pen, IPath path, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IPen<TPixel> pen, IPath path, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, null, pen, path, options);
@ -143,7 +143,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, IPath path)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, IPath path)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, brush, pen, path, TextGraphicsOptions.Default);
@ -163,16 +163,11 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, IPath path, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, IPath path, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
float dpiX = DefaultTextDpi;
float dpiY = DefaultTextDpi;
if (options.UseImageResolution)
{
dpiX = (float)source.MetaData.HorizontalResolution;
dpiY = (float)source.MetaData.VerticalResolution;
}
var style = new RendererOptions(font, dpiX, dpiY)
{

21
src/ImageSharp.Drawing/Text/DrawText.cs

@ -34,7 +34,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, TPixel color, PointF location)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, TPixel color, PointF location)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, color, location, TextGraphicsOptions.Default);
@ -53,7 +53,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, TPixel color, PointF location, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, TPixel color, PointF location, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, Brushes.Solid(color), null, location, options);
@ -71,7 +71,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IBrush<TPixel> brush, PointF location)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, PointF location)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, brush, location, TextGraphicsOptions.Default);
@ -90,7 +90,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IBrush<TPixel> brush, PointF location, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, PointF location, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, brush, null, location, options);
@ -108,7 +108,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IPen<TPixel> pen, PointF location)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IPen<TPixel> pen, PointF location)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, pen, location, TextGraphicsOptions.Default);
@ -127,7 +127,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IPen<TPixel> pen, PointF location, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IPen<TPixel> pen, PointF location, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, null, pen, location, options);
@ -146,7 +146,7 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, brush, pen, location, TextGraphicsOptions.Default);
@ -166,16 +166,11 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Image{TPixel}" />.
/// </returns>
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location, TextGraphicsOptions options)
public static IImageProcessingContext<TPixel> DrawText<TPixel>(this IImageProcessingContext<TPixel> source, string text, Font font, IBrush<TPixel> brush, IPen<TPixel> pen, PointF location, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
float dpiX = DefaultTextDpi;
float dpiY = DefaultTextDpi;
if (options.UseImageResolution)
{
dpiX = (float)source.MetaData.HorizontalResolution;
dpiY = (float)source.MetaData.VerticalResolution;
}
var style = new RendererOptions(font, dpiX, dpiY, location)
{

9
src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs

@ -29,8 +29,6 @@ namespace ImageSharp.Drawing
private PixelBlenderMode blenderMode;
private bool? useImageResolution;
private float wrapTextWidth;
private SixLabors.Fonts.HorizontalAlignment? horizontalAlignment;
@ -44,7 +42,6 @@ namespace ImageSharp.Drawing
{
this.applyKerning = true;
this.tabWidth = 4;
this.useImageResolution = false;
this.wrapTextWidth = 0;
this.horizontalAlignment = HorizontalAlignment.Left;
this.verticalAlignment = VerticalAlignment.Top;
@ -89,12 +86,6 @@ namespace ImageSharp.Drawing
/// </summary>
public float TabWidth { get => this.tabWidth ?? 4; set => this.tabWidth = value; }
/// <summary>
/// Gets or sets a value indicating whether to use the current image resultion to for point size scaling.
/// If this is [false] the text renders at 72dpi otherwise it renders at Image resolution
/// </summary>
public bool UseImageResolution { get => this.useImageResolution ?? false; set => this.useImageResolution = value; }
/// <summary>
/// Gets or sets a value indicating if greater than zero determine the width at which text should wrap.
/// </summary>

107
src/ImageSharp/ApplyProcessors.cs

@ -0,0 +1,107 @@
// <copyright file="ApplyProcessors.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
/// <summary>
/// Extension methods for the <see cref="Image{TPixel}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Mutates the image by applying the image operation to it.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="operation">The operations to perform on the source.</param>
public static void Mutate<TPixel>(this Image<TPixel> source, Action<IImageProcessingContext<TPixel>> operation)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(operation, nameof(operation));
Guard.NotNull(source, nameof(source));
IInternalImageProcessingContext<TPixel> operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, true);
operation(operationsRunner);
operationsRunner.Apply();
}
/// <summary>
/// Mutates the image by applying the operations to it.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="operations">The operations to perform on the source.</param>
public static void Mutate<TPixel>(this Image<TPixel> source, params IImageProcessor<TPixel>[] operations)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(operations, nameof(operations));
Guard.NotNull(source, nameof(source));
IInternalImageProcessingContext<TPixel> operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, true);
operationsRunner.ApplyProcessors(operations);
operationsRunner.Apply();
}
/// <summary>
/// Clones the current image mutating the clone by applying the operation to it.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="operation">The operations to perform on the source.</param>
/// <returns>Anew Image which has teh data from the <paramref name="source"/> but with the <paramref name="operation"/> applied.</returns>
public static Image<TPixel> Clone<TPixel>(this Image<TPixel> source, Action<IImageProcessingContext<TPixel>> operation)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(operation, nameof(operation));
Guard.NotNull(source, nameof(source));
IInternalImageProcessingContext<TPixel> operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, false);
operation(operationsRunner);
return operationsRunner.Apply();
}
/// <summary>
/// Clones the current image mutating the clone by applying the operations to it.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="operations">The operations to perform on the source.</param>
/// <returns>Anew Image which has teh data from the <paramref name="source"/> but with the <paramref name="operations"/> applied.</returns>
public static Image<TPixel> Clone<TPixel>(this Image<TPixel> source, params IImageProcessor<TPixel>[] operations)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(operations, nameof(operations));
Guard.NotNull(source, nameof(source));
IInternalImageProcessingContext<TPixel> operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, false);
operationsRunner.ApplyProcessors(operations);
return operationsRunner.Apply();
}
/// <summary>
/// Applies all the ImageProcessors agains the operation
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="operations">The operations to perform on the source.</param>
/// <returns>returns the current operations class to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> ApplyProcessors<TPixel>(this IImageProcessingContext<TPixel> source, params IImageProcessor<TPixel>[] operations)
where TPixel : struct, IPixel<TPixel>
{
foreach (IImageProcessor<TPixel> p in operations)
{
source = source.ApplyProcessor(p);
}
return source;
}
}
}

7
src/ImageSharp/Configuration.cs

@ -103,11 +103,16 @@ namespace ImageSharp
#if !NETSTANDARD1_1
/// <summary>
/// Gets or sets the fielsystem helper for accessing the local file system.
/// Gets or sets the filesystem helper for accessing the local file system.
/// </summary>
internal IFileSystem FileSystem { get; set; } = new LocalFileSystem();
#endif
/// <summary>
/// Gets or sets the image operations providers.
/// </summary>
internal IImageProcessingContextFactory ImageOperationsProvider { get; set; } = new DefaultImageOperationsProvider();
/// <summary>
/// Registers a new format provider.
/// </summary>

78
src/ImageSharp/DefaultInternalImageProcessorContext.cs

@ -0,0 +1,78 @@
// <copyright file="DefaultInternalImageProcessorApplicator.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
using SixLabors.Primitives;
/// <summary>
/// Performs processor application operations on the source image
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
internal class DefaultInternalImageProcessorContext<TPixel> : IInternalImageProcessingContext<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly bool mutate;
private readonly Image<TPixel> source;
private Image<TPixel> destination;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultInternalImageProcessorContext{TPixel}"/> class.
/// </summary>
/// <param name="source">The image.</param>
/// <param name="mutate">The mutate.</param>
public DefaultInternalImageProcessorContext(Image<TPixel> source, bool mutate)
{
this.mutate = mutate;
this.source = source;
if (this.mutate)
{
this.destination = source;
}
}
/// <inheritdoc/>
public Image<TPixel> Apply()
{
if (!this.mutate && this.destination == null)
{
// Ensure we have cloned it if we are not mutating as we might have failed to register any Processors
this.destination = this.source.Clone();
}
return this.destination;
}
/// <inheritdoc/>
public IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle)
{
if (!this.mutate && this.destination == null)
{
// This will only work if the first processor applied is the cloning one thus
// realistically for this optermissation to work the resize must the first processor
// applied any only up processors will take the douple data path.
var cloningImageProcessor = processor as ICloningImageProcessor<TPixel>;
if (cloningImageProcessor != null)
{
this.destination = cloningImageProcessor.CloneAndApply(this.source, rectangle);
return this;
}
this.destination = this.source.Clone();
}
processor.Apply(this.destination, rectangle);
return this;
}
/// <inheritdoc/>
public IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor)
{
return this.ApplyProcessor(processor, this.source.Bounds());
}
}
}

19
src/ImageSharp/Formats/Bmp/ImageExtensions.cs

@ -24,11 +24,20 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>
/// The <see cref="Image{TPixel}"/>.
/// </returns>
public static Image<TPixel> SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream)
public static void SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream)
where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, new BmpEncoder());
=> source.SaveAsBmp(stream, null);
/// <summary>
/// Saves the image to the given stream with the bmp format.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsBmp<TPixel>(this Image<TPixel> source, Stream stream, BmpEncoder encoder)
where TPixel : struct, IPixel<TPixel>
=> source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Bitmap));
}
}

21
src/ImageSharp/Formats/Gif/ImageExtensions.cs

@ -24,14 +24,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>
/// The <see cref="Image{TPixel}"/>.
/// </returns>
public static Image<TPixel> SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream)
public static void SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
return SaveAsGif(source, stream, null);
}
=> source.SaveAsGif(stream, null);
/// <summary>
/// Saves the image to the given stream with the gif format.
@ -41,16 +36,8 @@ namespace ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>
/// The <see cref="Image{TPixel}"/>.
/// </returns>
public static Image<TPixel> SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream, GifEncoder encoder)
public static void SaveAsGif<TPixel>(this Image<TPixel> source, Stream stream, GifEncoder encoder)
where TPixel : struct, IPixel<TPixel>
{
encoder = encoder ?? new GifEncoder();
encoder.Encode(source, stream);
return source;
}
=> source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Gif));
}
}

21
src/ImageSharp/Formats/Jpeg/ImageExtensions.cs

@ -24,14 +24,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>
/// The <see cref="Image{TPixel}"/>.
/// </returns>
public static Image<TPixel> SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream)
public static void SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
return SaveAsJpeg(source, stream, null);
}
=> SaveAsJpeg(source, stream, null);
/// <summary>
/// Saves the image to the given stream with the jpeg format.
@ -41,16 +36,8 @@ namespace ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>
/// The <see cref="Image{TPixel}"/>.
/// </returns>
public static Image<TPixel> SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream, JpegEncoder encoder)
public static void SaveAsJpeg<TPixel>(this Image<TPixel> source, Stream stream, JpegEncoder encoder)
where TPixel : struct, IPixel<TPixel>
{
encoder = encoder ?? new JpegEncoder();
encoder.Encode(source, stream);
return source;
}
=> source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Jpeg));
}
}

21
src/ImageSharp/Formats/Png/ImageExtensions.cs

@ -23,14 +23,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>
/// The <see cref="Image{TPixel}"/>.
/// </returns>
public static Image<TPixel> SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream)
public static void SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
return SaveAsPng(source, stream, null);
}
=> SaveAsPng(source, stream, null);
/// <summary>
/// Saves the image to the given stream with the png format.
@ -40,16 +35,8 @@ namespace ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>
/// The <see cref="Image{TPixel}"/>.
/// </returns>
public static Image<TPixel> SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream, PngEncoder encoder)
public static void SaveAsPng<TPixel>(this Image<TPixel> source, Stream stream, PngEncoder encoder)
where TPixel : struct, IPixel<TPixel>
{
encoder = encoder ?? new PngEncoder();
encoder.Encode(source, stream);
return source;
}
=> source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Png));
}
}

38
src/ImageSharp/IImageProcessingContextFactory.cs

@ -0,0 +1,38 @@
// <copyright file="IImageProcessorApplicatorFactory.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using ImageSharp.PixelFormats;
/// <summary>
/// Represents an interface that will create IInternalImageProcessingContext instances
/// </summary>
internal interface IImageProcessingContextFactory
{
/// <summary>
/// Called during Mutate operations to generate the image operations provider.
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
/// <param name="source">The source image.</param>
/// <param name="mutate">A flag to determin with the image operations is allowed to mutate the source image or not.</param>
/// <returns>A new IImageOPeration</returns>
IInternalImageProcessingContext<TPixel> CreateImageProcessingContext<TPixel>(Image<TPixel> source, bool mutate)
where TPixel : struct, IPixel<TPixel>;
}
/// <summary>
/// The default implmentation of IImageOperationsProvider
/// </summary>
internal class DefaultImageOperationsProvider : IImageProcessingContextFactory
{
/// <inheritdoc/>
public IInternalImageProcessingContext<TPixel> CreateImageProcessingContext<TPixel>(Image<TPixel> source, bool mutate)
where TPixel : struct, IPixel<TPixel>
{
return new DefaultInternalImageProcessorContext<TPixel>(source, mutate);
}
}
}

48
src/ImageSharp/IImageProcessingContext{TPixel}.cs

@ -0,0 +1,48 @@
// <copyright file="IImageProcessorApplicator.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
using SixLabors.Primitives;
/// <summary>
/// An interface to queue up image operations.
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
public interface IImageProcessingContext<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Adds the processor to the current set of image operations to be applied.
/// </summary>
/// <param name="processor">The processor to apply</param>
/// <param name="rectangle">The area to apply it to</param>
/// <returns>The current operations class to allow chaining of operations.</returns>
IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle);
/// <summary>
/// Adds the processor to the current set of image operations to be applied.
/// </summary>
/// <param name="processor">The processor to apply</param>
/// <returns>The current operations class to allow chaining of operations.</returns>
IImageProcessingContext<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor);
}
/// <summary>
/// An internal interface to queue up image operations and have a method to apply them to and return a result
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
internal interface IInternalImageProcessingContext<TPixel> : IImageProcessingContext<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Adds the processors to the current image
/// </summary>
/// <returns>The current image or a new image depending on withere this is alloed to mutate the source image.</returns>
Image<TPixel> Apply();
}
}

34
src/ImageSharp/Image/ICloningImageProcessor.cs

@ -0,0 +1,34 @@
// <copyright file="ICloningImageProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Processing
{
using ImageSharp.PixelFormats;
using SixLabors.Primitives;
/// <summary>
/// Encapsulates methods to alter the pixels of a new image, cloned from the original image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal interface ICloningImageProcessor<TPixel> : IImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageBase{TPixel}"/>.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="source"/> is null.
/// </exception>
/// <exception cref="System.ArgumentException">
/// <paramref name="sourceRectangle"/> doesnt fit the dimension of the image.
/// </exception>
/// <returns>Returns the cloned image after thre processor has been applied to it.</returns>
Image<TPixel> CloneAndApply(Image<TPixel> source, Rectangle sourceRectangle);
}
}

10
src/ImageSharp/Image/IImageBase.cs

@ -12,11 +12,6 @@ namespace ImageSharp
/// </summary>
public interface IImageBase
{
/// <summary>
/// Gets the <see cref="Rectangle"/> representing the bounds of the image.
/// </summary>
Rectangle Bounds { get; }
/// <summary>
/// Gets the width in pixels.
/// </summary>
@ -27,11 +22,6 @@ namespace ImageSharp
/// </summary>
int Height { get; }
/// <summary>
/// Gets the pixel ratio made up of the width and height.
/// </summary>
double PixelRatio { get; }
/// <summary>
/// Gets the configuration providing initialization code which allows extending the library.
/// </summary>

2
src/ImageSharp/Image/IImageProcessor.cs

@ -42,6 +42,6 @@ namespace ImageSharp.Processing
/// <exception cref="System.ArgumentException">
/// <paramref name="sourceRectangle"/> doesnt fit the dimension of the image.
/// </exception>
void Apply(ImageBase<TPixel> source, Rectangle sourceRectangle);
void Apply(Image<TPixel> source, Rectangle sourceRectangle);
}
}

51
src/ImageSharp/Image/ImageBase{TPixel}.cs

@ -19,7 +19,6 @@ namespace ImageSharp
/// images in different pixel formats.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
[DebuggerDisplay("Image: {Width}x{Height}")]
public abstract class ImageBase<TPixel> : IImageBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
@ -105,12 +104,8 @@ namespace ImageSharp
// Rent then copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here.
this.RentPixels();
using (PixelAccessor<TPixel> sourcePixels = other.Lock())
using (PixelAccessor<TPixel> target = this.Lock())
{
// Check we can do this without crashing
sourcePixels.CopyTo(target);
}
other.Pixels.CopyTo(this.Pixels);
}
/// <inheritdoc/>
@ -122,12 +117,6 @@ namespace ImageSharp
/// <inheritdoc/>
public int Height { get; private set; }
/// <inheritdoc/>
public double PixelRatio => (double)this.Width / this.Height;
/// <inheritdoc/>
public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height);
/// <summary>
/// Gets the configuration providing initialization code which allows extending the library.
/// </summary>
@ -195,13 +184,12 @@ namespace ImageSharp
}
/// <summary>
/// Applies the processor.
/// Clones the image
/// </summary>
/// <param name="processor">The processor.</param>
/// <param name="rectangle">The rectangle.</param>
public virtual void ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle)
/// <returns>A new items which is a clone of the original.</returns>
public ImageBase<TPixel> Clone()
{
processor.Apply(this, rectangle);
return this.CloneInternal();
}
/// <inheritdoc />
@ -256,6 +244,33 @@ namespace ImageSharp
this.PixelBuffer = newPixels;
}
/// <summary>
/// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer.
/// </summary>
/// <param name="pixelSource">The pixel source.</param>
internal void SwapPixelsData(ImageBase<TPixel> pixelSource)
{
Guard.NotNull(pixelSource, nameof(pixelSource));
int newWidth = pixelSource.Width;
int newHeight = pixelSource.Height;
TPixel[] newPixels = pixelSource.PixelBuffer;
pixelSource.PixelBuffer = this.PixelBuffer;
pixelSource.Width = this.Width;
pixelSource.Height = this.Height;
this.Width = newWidth;
this.Height = newHeight;
this.PixelBuffer = newPixels;
}
/// <summary>
/// Clones the image
/// </summary>
/// <returns>A new items which is a clone of the original.</returns>
protected abstract ImageBase<TPixel> CloneInternal();
/// <summary>
/// Copies the properties from the other <see cref="IImageBase"/>.
/// </summary>

153
src/ImageSharp/Image/ImageExtensions.cs

@ -0,0 +1,153 @@
// <copyright file="ImageExtensions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ImageSharp.Formats;
using ImageSharp.PixelFormats;
using SixLabors.Primitives;
/// <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 ImageBase<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 ImageBase<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> new Size(source.Width, source.Height);
#if !NETSTANDARD1_1
/// <summary>
/// Saves the image to the given stream using the currently loaded image format.
/// </summary>
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param>
/// <param name="filePath">The file path to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, string filePath)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNullOrEmpty(filePath, nameof(filePath));
string ext = Path.GetExtension(filePath).Trim('.');
IImageFormat format = source.Configuration.FindFormatByFileExtensions(ext);
if (format == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:");
foreach (IImageFormat fmt in source.Configuration.ImageFormats)
{
stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}");
}
throw new NotSupportedException(stringBuilder.ToString());
}
IImageEncoder encoder = source.Configuration.FindEncoder(format);
if (encoder == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in source.Configuration.ImageEncoders)
{
stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}");
}
throw new NotSupportedException(stringBuilder.ToString());
}
source.Save(filePath, encoder);
}
/// <summary>
/// Saves the image to the given stream using the currently loaded image format.
/// </summary>
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param>
/// <param name="filePath">The file path to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the encoder is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, string filePath, IImageEncoder encoder)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(encoder, nameof(encoder));
using (Stream fs = source.Configuration.FileSystem.Create(filePath))
{
source.Save(fs, encoder);
}
}
#endif
/// <summary>
/// Saves the image to the given stream using the currently loaded image format.
/// </summary>
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="format">The format to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void Save<TPixel>(this Image<TPixel> source, Stream stream, IImageFormat format)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(format, nameof(format));
IImageEncoder encoder = source.Configuration.FindEncoder(format);
if (encoder == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> val in source.Configuration.ImageEncoders)
{
stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
}
throw new NotSupportedException(stringBuilder.ToString());
}
source.Save(stream, encoder);
}
/// <summary>
/// Returns a Base64 encoded string from the given image.
/// </summary>
/// <example><see href="data:image/gif;base64,R0lGODlhAQABAIABAEdJRgAAACwAAAAAAQABAAACAkQBAA=="/></example>
/// <typeparam name="TPixel">The Pixel format.</typeparam>
/// <param name="source">The source image</param>
/// <param name="format">The format.</param>
/// <returns>The <see cref="string"/></returns>
public static string ToBase64String<TPixel>(this Image<TPixel> source, IImageFormat format)
where TPixel : struct, IPixel<TPixel>
{
using (var stream = new MemoryStream())
{
source.Save(stream, format);
stream.Flush();
return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}";
}
}
}
}

63
src/ImageSharp/Image/ImageFrame{TPixel}.cs

@ -14,64 +14,97 @@ namespace ImageSharp
/// Represents a single frame in a animation.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
public class ImageFrame<TPixel> : ImageBase<TPixel>, IImageFrame
public sealed class ImageFrame<TPixel> : ImageBase<TPixel>, IImageFrame
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}"/> class.
/// </summary>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
public ImageFrame(Configuration configuration, int width, int height)
: base(configuration, width, height)
{
this.MetaData = new ImageFrameMetaData();
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}"/> class.
/// </summary>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
public ImageFrame(int width, int height, Configuration configuration = null)
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The metadata of the frame.</param>
public ImageFrame(Configuration configuration, int width, int height, ImageFrameMetaData metadata)
: base(configuration, width, height)
{
Guard.NotNull(metadata, nameof(metadata));
this.MetaData = metadata;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageFrame{TPixel}"/> class.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
public ImageFrame(int width, int height)
: this(null, width, height)
{
this.MetaData = new ImageFrameMetaData();
}
/// <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(ImageFrame<TPixel> image)
internal ImageFrame(ImageBase<TPixel> image)
: base(image)
{
this.CopyProperties(image);
this.MetaData = new ImageFrameMetaData();
}
/// <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)
private ImageFrame(ImageFrame<TPixel> image)
: base(image)
{
this.CopyProperties(image);
}
/// <summary>
/// Gets the meta data of the frame.
/// </summary>
public ImageFrameMetaData MetaData { get; private set; } = new ImageFrameMetaData();
public ImageFrameMetaData MetaData { get; private set; }
/// <inheritdoc/>
public override string ToString()
{
return $"ImageFrame: {this.Width}x{this.Height}";
return $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}";
}
/// <summary>
/// Returns a copy of the image frame in the given pixel format.
/// </summary>
/// <param name="scaleFunc">A function that allows for the correction of vector scaling between unknown color formats.</param>
/// <typeparam name="TPixel2">The pixel format.</typeparam>
/// <returns>The <see cref="ImageFrame{TPixel2}"/></returns>
public ImageFrame<TPixel2> To<TPixel2>(Func<Vector4, Vector4> scaleFunc = null)
public ImageFrame<TPixel2> CloneAs<TPixel2>()
where TPixel2 : struct, IPixel<TPixel2>
{
scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TPixel, TPixel2>(scaleFunc);
if (typeof(TPixel2) == typeof(TPixel))
{
return this.Clone() as ImageFrame<TPixel2>;
}
ImageFrame<TPixel2> target = new ImageFrame<TPixel2>(this.Width, this.Height, this.Configuration);
Func<Vector4, Vector4> scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TPixel, TPixel2>();
var target = new ImageFrame<TPixel2>(this.Configuration, this.Width, this.Height);
target.CopyProperties(this);
using (PixelAccessor<TPixel> pixels = this.Lock())
@ -99,11 +132,17 @@ namespace ImageSharp
/// Clones the current instance.
/// </summary>
/// <returns>The <see cref="ImageFrame{TPixel}"/></returns>
internal virtual ImageFrame<TPixel> Clone()
public new ImageFrame<TPixel> Clone()
{
return new ImageFrame<TPixel>(this);
}
/// <inheritdoc/>
protected override ImageBase<TPixel> CloneInternal()
{
return this.Clone();
}
/// <summary>
/// Copies the properties from the other <see cref="IImageFrame"/>.
/// </summary>

32
src/ImageSharp/Image/ImageProcessingExtensions.cs

@ -1,32 +0,0 @@
// <copyright file="ImageProcessingExtensions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
/// <summary>
/// Extension methods for the <see cref="Image{TPixel}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Applies the processor to the image.
/// <remarks>This method does not resize the target image.</remarks>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="processor">The processor to apply to the image.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Apply<TPixel>(this Image<TPixel> source, IImageProcessor<TPixel> processor)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(processor, source.Bounds);
return source;
}
}
}

212
src/ImageSharp/Image/Image{TPixel}.cs

@ -22,8 +22,7 @@ namespace ImageSharp
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
[DebuggerDisplay("Image: {Width}x{Height}")]
public class Image<TPixel> : ImageBase<TPixel>, IImage
public sealed class Image<TPixel> : ImageBase<TPixel>, IImage
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
@ -51,20 +50,36 @@ namespace ImageSharp
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images metadata.</param>
internal Image(Configuration configuration, int width, int height, ImageMetaData metadata)
: base(configuration, width, height)
{
this.MetaData = metadata ?? new ImageMetaData();
}
/// <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(Image<TPixel> other)
private Image(Image<TPixel> other)
: base(other)
{
foreach (ImageFrame<TPixel> frame in other.Frames)
{
if (frame != null)
{
this.Frames.Add(new ImageFrame<TPixel>(frame));
this.Frames.Add(frame.Clone());
}
}
@ -77,182 +92,44 @@ namespace ImageSharp
/// </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)
private Image(ImageBase<TPixel> other)
: base(other)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images metadata.</param>
internal Image(Configuration configuration, int width, int height, ImageMetaData metadata)
: base(configuration, width, height)
{
this.MetaData = metadata ?? new ImageMetaData();
}
/// <summary>
/// Gets the meta data of the image.
/// </summary>
public ImageMetaData MetaData { get; private set; } = new ImageMetaData();
/// <summary>
/// Gets the width of the image in inches. It is calculated as the width of the image
/// in pixels multiplied with the density. When the density is equals or less than zero
/// the default value is used.
/// </summary>
/// <value>The width of the image in inches.</value>
public double InchWidth => this.Width / this.MetaData.HorizontalResolution;
/// <summary>
/// Gets the height of the image in inches. It is calculated as the height of the image
/// in pixels multiplied with the density. When the density is equals or less than zero
/// the default value is used.
/// </summary>
/// <value>The height of the image in inches.</value>
public double InchHeight => this.Height / this.MetaData.VerticalResolution;
/// <summary>
/// Gets a value indicating whether this image is animated.
/// </summary>
/// <value>
/// <c>True</c> if this image is animated; otherwise, <c>false</c>.
/// </value>
public bool IsAnimated => this.Frames.Count > 0;
/// <summary>
/// Gets the other frames for the animation.
/// Gets the other frames associated with this image.
/// </summary>
/// <value>The list of frame images.</value>
public IList<ImageFrame<TPixel>> Frames { get; } = new List<ImageFrame<TPixel>>();
/// <summary>
/// Applies the processor to the image.
/// </summary>
/// <param name="processor">The processor to apply to the image.</param>
/// <param name="rectangle">The <see cref="Rectangle" /> structure that specifies the portion of the image object to draw.</param>
public override void ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle)
{
// we want to put this on on here as it gives us a really go place to test/verify processor settings
base.ApplyProcessor(processor, rectangle);
foreach (ImageFrame<TPixel> sourceFrame in this.Frames)
{
sourceFrame.ApplyProcessor(processor, rectangle);
}
}
/// <summary>
/// Saves the image to the given stream using the currently loaded image format.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="format">The format to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public Image<TPixel> Save(Stream stream, IImageFormat format)
{
Guard.NotNull(format, nameof(format));
IImageEncoder encoder = this.Configuration.FindEncoder(format);
if (encoder == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> val in this.Configuration.ImageEncoders)
{
stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
}
throw new NotSupportedException(stringBuilder.ToString());
}
return this.Save(stream, encoder);
}
/// <summary>
/// Saves the image to the given stream using the given image encoder.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream or encoder is null.</exception>
/// <returns>
/// The <see cref="Image{TPixel}"/>.
/// </returns>
public Image<TPixel> Save(Stream stream, IImageEncoder encoder)
public void Save(Stream stream, IImageEncoder encoder)
{
Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoder, nameof(encoder));
encoder.Encode(this, stream);
return this;
}
#if !NETSTANDARD1_1
/// <summary>
/// Saves the image to the given stream using the currently loaded image format.
/// </summary>
/// <param name="filePath">The file path to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public Image<TPixel> Save(string filePath)
{
Guard.NotNullOrEmpty(filePath, nameof(filePath));
string ext = Path.GetExtension(filePath).Trim('.');
var format = this.Configuration.FindFormatByFileExtensions(ext);
if (format == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:");
foreach (IImageFormat fmt in this.Configuration.ImageFormats)
{
stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}");
}
throw new NotSupportedException(stringBuilder.ToString());
}
IImageEncoder encoder = this.Configuration.FindEncoder(format);
if (encoder == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:");
foreach (KeyValuePair<IImageFormat, IImageEncoder> enc in this.Configuration.ImageEncoders)
{
stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}");
}
throw new NotSupportedException(stringBuilder.ToString());
}
return this.Save(filePath, encoder);
}
/// <summary>
/// Saves the image to the given stream using the currently loaded image format.
/// Clones the current image
/// </summary>
/// <param name="filePath">The file path to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the encoder is null.</exception>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public Image<TPixel> Save(string filePath, IImageEncoder encoder)
/// <returns>Returns a new image with all the same metadata as the original.</returns>
public new Image<TPixel> Clone()
{
Guard.NotNull(encoder, nameof(encoder));
using (Stream fs = this.Configuration.FileSystem.Create(filePath))
{
return this.Save(fs, encoder);
}
return new Image<TPixel>(this);
}
#endif
/// <inheritdoc/>
public override string ToString()
@ -260,32 +137,21 @@ namespace ImageSharp
return $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}";
}
/// <summary>
/// Returns a Base64 encoded string from the given image.
/// </summary>
/// <example><see href="data:image/gif;base64,R0lGODlhAQABAIABAEdJRgAAACwAAAAAAQABAAACAkQBAA=="/></example>
/// <param name="format">The format.</param>
/// <returns>The <see cref="string"/></returns>
public string ToBase64String(IImageFormat format)
{
using (var stream = new MemoryStream())
{
this.Save(stream, format);
stream.Flush();
return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}";
}
}
/// <summary>
/// Returns a copy of the image in the given pixel format.
/// </summary>
/// <param name="scaleFunc">A function that allows for the correction of vector scaling between unknown color formats.</param>
/// <typeparam name="TPixel2">The pixel format.</typeparam>
/// <returns>The <see cref="Image{TPixel2}"/></returns>
public Image<TPixel2> To<TPixel2>(Func<Vector4, Vector4> scaleFunc = null)
public Image<TPixel2> CloneAs<TPixel2>()
where TPixel2 : struct, IPixel<TPixel2>
{
scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TPixel, TPixel2>(scaleFunc);
if (typeof(TPixel2) == typeof(TPixel))
{
// short circuit when same pixel types
return this.Clone() as Image<TPixel2>;
}
Func<Vector4, Vector4> scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TPixel, TPixel2>();
var target = new Image<TPixel2>(this.Configuration, this.Width, this.Height);
target.CopyProperties(this);
@ -310,7 +176,7 @@ namespace ImageSharp
for (int i = 0; i < this.Frames.Count; i++)
{
target.Frames.Add(this.Frames[i].To<TPixel2>());
target.Frames.Add(this.Frames[i].CloneAs<TPixel2>());
}
return target;
@ -320,7 +186,7 @@ namespace ImageSharp
/// Creates a new <see cref="ImageFrame{TPixel}"/> from this instance
/// </summary>
/// <returns>The <see cref="ImageFrame{TPixel}"/></returns>
internal virtual ImageFrame<TPixel> ToFrame()
internal ImageFrame<TPixel> ToFrame()
{
return new ImageFrame<TPixel>(this);
}
@ -337,6 +203,12 @@ namespace ImageSharp
base.Dispose(disposing);
}
/// <inheritdoc/>
protected override ImageBase<TPixel> CloneInternal()
{
return this.Clone();
}
/// <summary>
/// Copies the properties from the other <see cref="IImage"/>.
/// </summary>

9
src/ImageSharp/MetaData/ImageFrameMetaData.cs

@ -39,5 +39,14 @@ namespace ImageSharp
/// <inheritdoc/>
public DisposalMethod DisposalMethod { get; set; }
/// <summary>
/// Clones this ImageFrameMetaData.
/// </summary>
/// <returns>The cloned instance.</returns>
public ImageFrameMetaData Clone()
{
return new ImageFrameMetaData(this);
}
}
}

9
src/ImageSharp/MetaData/ImageMetaData.cs

@ -132,6 +132,15 @@ namespace ImageSharp
/// </summary>
public ushort RepeatCount { get; set; }
/// <summary>
/// Clones this into a new instance
/// </summary>
/// <returns>The cloned metadata instance</returns>
public ImageMetaData Clone()
{
return new ImageMetaData(this);
}
/// <summary>
/// Synchronizes the profiles with the current meta data.
/// </summary>

131
src/ImageSharp/Numerics/ValueSize.cs

@ -0,0 +1,131 @@
// <copyright file="LongRational.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using SixLabors.Primitives;
/// <summary>
/// Represents a value in relation to a value on the image
/// </summary>
internal struct ValueSize : IEquatable<ValueSize>
{
/// <summary>
/// Initializes a new instance of the <see cref="ValueSize"/> struct.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="type">The type.</param>
public ValueSize(float value, ValueSizeType type)
{
if (type != ValueSizeType.Absolute)
{
Guard.MustBeBetweenOrEqualTo(value, 0, 1, nameof(value));
}
this.Value = value;
this.Type = type;
}
/// <summary>
/// The different vlaue types
/// </summary>
public enum ValueSizeType
{
/// <summary>
/// The value is the final return value
/// </summary>
Absolute,
/// <summary>
/// The value is a percentage of the Images Width
/// </summary>
PercentageOfWidth,
/// <summary>
/// The value is a percentage of the Images height
/// </summary>
PercentageOfHeight
}
/// <summary>
/// Gets the value.
/// </summary>
public float Value { get; }
/// <summary>
/// Gets the type.
/// </summary>
public ValueSizeType Type { get; }
/// <summary>
/// Implicitly converts a float into an absolute value
/// </summary>
/// <param name="d">the vlaue to use as the absolute figure.</param>
public static implicit operator ValueSize(float d)
=> Absolute(d);
/// <summary>
/// Create a new ValueSize with as a PercentageOfWidth type with value set to percentage.
/// </summary>
/// <param name="percentage">The percentage.</param>
/// <returns>a Values size with type PercentageOfWidth</returns>
public static ValueSize PercentageOfWidth(float percentage)
{
return new ValueSize(percentage, ValueSizeType.PercentageOfWidth);
}
/// <summary>
/// Create a new ValueSize with as a PercentageOfHeight type with value set to percentage.
/// </summary>
/// <param name="percentage">The percentage.</param>
/// <returns>a Values size with type PercentageOfHeight</returns>
public static ValueSize PercentageOfHeight(float percentage)
{
return new ValueSize(percentage, ValueSizeType.PercentageOfHeight);
}
/// <summary>
/// Create a new ValueSize with as a Absolute type with value set to value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>a Values size with type Absolute(</returns>
public static ValueSize Absolute(float value)
{
return new ValueSize(value, ValueSizeType.Absolute);
}
/// <summary>
/// Calculates the specified size.
/// </summary>
/// <param name="size">The size.</param>
/// <returns>The calucalted value</returns>
public float Calculate(Size size)
{
switch (this.Type)
{
case ValueSizeType.PercentageOfWidth:
return this.Value * size.Width;
case ValueSizeType.PercentageOfHeight:
return this.Value * size.Height;
case ValueSizeType.Absolute:
default:
return this.Value;
}
}
/// <inheritdoc/>
public override string ToString()
{
return $"{this.Value} - {this.Type}";
}
/// <inheritdoc/>
public bool Equals(ValueSize other)
{
return this.Type == other.Type && this.Value == other.Value;
}
}
}

9
src/ImageSharp/PixelFormats/PackedPixelConverterHelper.cs

@ -21,18 +21,11 @@ namespace ImageSharp.PixelFormats
/// <summary>
/// Returns the correct scaling function for the given types The compute scale function.
/// </summary>
/// <param name="scaleFunc">The scale function.</param>
/// <typeparam name="TPixel">The source pixel format.</typeparam>
/// <typeparam name="TPixel2">The target pixel format.</typeparam>
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
public static Func<Vector4, Vector4> ComputeScaleFunction<TPixel, TPixel2>(Func<Vector4, Vector4> scaleFunc)
public static Func<Vector4, Vector4> ComputeScaleFunction<TPixel, TPixel2>()
{
// Custom type with a custom function.
if (scaleFunc != null)
{
return scaleFunc;
}
Type source = typeof(TPixel);
Type target = typeof(TPixel2);

7
src/ImageSharp/Processing/Binarization/BinaryThreshold.cs

@ -24,10 +24,11 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BinaryThreshold<TPixel>(this Image<TPixel> source, float threshold)
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold)
where TPixel : struct, IPixel<TPixel>
{
return BinaryThreshold(source, threshold, source.Bounds);
source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold));
return source;
}
/// <summary>
@ -40,7 +41,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BinaryThreshold<TPixel>(this Image<TPixel> source, float threshold, Rectangle rectangle)
public static IImageProcessingContext<TPixel> BinaryThreshold<TPixel>(this IImageProcessingContext<TPixel> source, float threshold, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new BinaryThresholdProcessor<TPixel>(threshold), rectangle);

45
src/ImageSharp/Processing/Binarization/Dither.cs

@ -17,6 +17,20 @@ namespace ImageSharp
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new OrderedDitherProcessor<TPixel>(dither, 0));
return source;
}
/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
/// </summary>
@ -25,10 +39,28 @@ namespace ImageSharp
/// <param name="dither">The ordered ditherer.</param>
/// <param name="index">The component index to test the threshold against. Must range from 0 to 3.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Dither<TPixel>(this Image<TPixel> source, IOrderedDither dither, int index = 0)
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, int index)
where TPixel : struct, IPixel<TPixel>
{
return Dither(source, dither, source.Bounds, index);
source.ApplyProcessor(new OrderedDitherProcessor<TPixel>(dither, index));
return source;
}
/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="dither">The ordered ditherer.</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{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new OrderedDitherProcessor<TPixel>(dither, 0), rectangle);
return source;
}
/// <summary>
@ -42,7 +74,7 @@ namespace ImageSharp
/// </param>
/// <param name="index">The component index to test the threshold against. Must range from 0 to 3.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Dither<TPixel>(this Image<TPixel> source, IOrderedDither dither, Rectangle rectangle, int index = 0)
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IOrderedDither dither, Rectangle rectangle, int index)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new OrderedDitherProcessor<TPixel>(dither, index), rectangle);
@ -57,10 +89,11 @@ namespace ImageSharp
/// <param name="diffuser">The diffusion algorithm to apply.</param>
/// <param name="threshold">The threshold to apply binarization of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Dither<TPixel>(this Image<TPixel> source, IErrorDiffuser diffuser, float threshold)
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold)
where TPixel : struct, IPixel<TPixel>
{
return Dither(source, diffuser, threshold, source.Bounds);
source.ApplyProcessor(new ErrorDiffusionDitherProcessor<TPixel>(diffuser, threshold));
return source;
}
/// <summary>
@ -74,7 +107,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Dither<TPixel>(this Image<TPixel> source, IErrorDiffuser diffuser, float threshold, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Dither<TPixel>(this IImageProcessingContext<TPixel> source, IErrorDiffuser diffuser, float threshold, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new ErrorDiffusionDitherProcessor<TPixel>(diffuser, threshold), rectangle);

7
src/ImageSharp/Processing/ColorMatrix/BlackWhite.cs

@ -24,10 +24,11 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BlackWhite<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> BlackWhite<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return BlackWhite(source, source.Bounds);
source.ApplyProcessor(new BlackWhiteProcessor<TPixel>());
return source;
}
/// <summary>
@ -39,7 +40,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BlackWhite<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> BlackWhite<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new BlackWhiteProcessor<TPixel>(), rectangle);

48
src/ImageSharp/Processing/ColorMatrix/ColorBlindness.cs

@ -25,10 +25,11 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="colorBlindness">The type of color blindness simulator to apply.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> ColorBlindness<TPixel>(this Image<TPixel> source, ColorBlindness colorBlindness)
public static IImageProcessingContext<TPixel> ColorBlindness<TPixel>(this IImageProcessingContext<TPixel> source, ColorBlindness colorBlindness)
where TPixel : struct, IPixel<TPixel>
{
return ColorBlindness(source, colorBlindness, source.Bounds);
source.ApplyProcessor(GetProcessor<TPixel>(colorBlindness));
return source;
}
/// <summary>
@ -41,48 +42,35 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> ColorBlindness<TPixel>(this Image<TPixel> source, ColorBlindness colorBlindness, Rectangle rectangle)
public static IImageProcessingContext<TPixel> ColorBlindness<TPixel>(this IImageProcessingContext<TPixel> source, ColorBlindness colorBlindness, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
IImageProcessor<TPixel> processor;
source.ApplyProcessor(GetProcessor<TPixel>(colorBlindness), rectangle);
return source;
}
private static IImageProcessor<TPixel> GetProcessor<TPixel>(ColorBlindness colorBlindness)
where TPixel : struct, IPixel<TPixel>
{
switch (colorBlindness)
{
case ImageSharp.Processing.ColorBlindness.Achromatomaly:
processor = new AchromatomalyProcessor<TPixel>();
break;
return new AchromatomalyProcessor<TPixel>();
case ImageSharp.Processing.ColorBlindness.Achromatopsia:
processor = new AchromatopsiaProcessor<TPixel>();
break;
return new AchromatopsiaProcessor<TPixel>();
case ImageSharp.Processing.ColorBlindness.Deuteranomaly:
processor = new DeuteranomalyProcessor<TPixel>();
break;
return new DeuteranomalyProcessor<TPixel>();
case ImageSharp.Processing.ColorBlindness.Deuteranopia:
processor = new DeuteranopiaProcessor<TPixel>();
break;
return new DeuteranopiaProcessor<TPixel>();
case ImageSharp.Processing.ColorBlindness.Protanomaly:
processor = new ProtanomalyProcessor<TPixel>();
break;
return new ProtanomalyProcessor<TPixel>();
case ImageSharp.Processing.ColorBlindness.Protanopia:
processor = new ProtanopiaProcessor<TPixel>();
break;
return new ProtanopiaProcessor<TPixel>();
case ImageSharp.Processing.ColorBlindness.Tritanomaly:
processor = new TritanomalyProcessor<TPixel>();
break;
return new TritanomalyProcessor<TPixel>();
default:
processor = new TritanopiaProcessor<TPixel>();
break;
return new TritanopiaProcessor<TPixel>();
}
source.ApplyProcessor(processor, rectangle);
return source;
}
}
}

20
src/ImageSharp/Processing/ColorMatrix/Grayscale.cs

@ -22,7 +22,7 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Grayscale<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return Grayscale(source, GrayscaleMode.Bt709);
@ -35,10 +35,15 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="mode">The formula to apply to perform the operation.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Grayscale<TPixel>(this Image<TPixel> source, GrayscaleMode mode)
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, GrayscaleMode mode)
where TPixel : struct, IPixel<TPixel>
{
return Grayscale(source, mode, source.Bounds);
IImageProcessor<TPixel> processor = mode == GrayscaleMode.Bt709
? (IImageProcessor<TPixel>)new GrayscaleBt709Processor<TPixel>()
: new GrayscaleBt601Processor<TPixel>();
source.ApplyProcessor(processor);
return source;
}
/// <summary>
@ -50,13 +55,10 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Grayscale<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
IImageProcessor<TPixel> processor = new GrayscaleBt709Processor<TPixel>();
source.ApplyProcessor(processor, rectangle);
return source;
return Grayscale(source, GrayscaleMode.Bt709, rectangle);
}
/// <summary>
@ -69,7 +71,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Grayscale<TPixel>(this Image<TPixel> source, GrayscaleMode mode, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Grayscale<TPixel>(this IImageProcessingContext<TPixel> source, GrayscaleMode mode, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
IImageProcessor<TPixel> processor = mode == GrayscaleMode.Bt709

7
src/ImageSharp/Processing/ColorMatrix/Hue.cs

@ -25,10 +25,11 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="degrees">The angle in degrees to adjust the image.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Hue<TPixel>(this Image<TPixel> source, float degrees)
public static IImageProcessingContext<TPixel> Hue<TPixel>(this IImageProcessingContext<TPixel> source, float degrees)
where TPixel : struct, IPixel<TPixel>
{
return Hue(source, degrees, source.Bounds);
source.ApplyProcessor(new HueProcessor<TPixel>(degrees));
return source;
}
/// <summary>
@ -41,7 +42,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Hue<TPixel>(this Image<TPixel> source, float degrees, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Hue<TPixel>(this IImageProcessingContext<TPixel> source, float degrees, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new HueProcessor<TPixel>(degrees), rectangle);

7
src/ImageSharp/Processing/ColorMatrix/Kodachrome.cs

@ -24,10 +24,11 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Kodachrome<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> Kodachrome<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return Kodachrome(source, source.Bounds);
source.ApplyProcessor(new KodachromeProcessor<TPixel>());
return source;
}
/// <summary>
@ -39,7 +40,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Kodachrome<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Kodachrome<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new KodachromeProcessor<TPixel>(), rectangle);

13
src/ImageSharp/Processing/ColorMatrix/Lomograph.cs

@ -24,10 +24,10 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Lomograph<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> Lomograph<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return Lomograph(source, source.Bounds, GraphicsOptions.Default);
return Lomograph(source, GraphicsOptions.Default);
}
/// <summary>
@ -39,7 +39,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Lomograph<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Lomograph<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return Lomograph(source, rectangle, GraphicsOptions.Default);
@ -52,10 +52,11 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Lomograph<TPixel>(this Image<TPixel> source, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Lomograph<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Lomograph(source, source.Bounds, options);
source.ApplyProcessor(new LomographProcessor<TPixel>(options));
return source;
}
/// <summary>
@ -68,7 +69,7 @@ namespace ImageSharp
/// </param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Lomograph<TPixel>(this Image<TPixel> source, Rectangle rectangle, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Lomograph<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new LomographProcessor<TPixel>(options), rectangle);

11
src/ImageSharp/Processing/ColorMatrix/Polaroid.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Polaroid<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> Polaroid<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return Polaroid(source, GraphicsOptions.Default);
@ -39,7 +39,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Polaroid<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Polaroid<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return Polaroid(source, rectangle, GraphicsOptions.Default);
@ -52,10 +52,11 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Polaroid<TPixel>(this Image<TPixel> source, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Polaroid<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Polaroid(source, source.Bounds, options);
source.ApplyProcessor(new PolaroidProcessor<TPixel>(options));
return source;
}
/// <summary>
@ -68,7 +69,7 @@ namespace ImageSharp
/// </param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Polaroid<TPixel>(this Image<TPixel> source, Rectangle rectangle, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Polaroid<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new PolaroidProcessor<TPixel>(options), rectangle);

7
src/ImageSharp/Processing/ColorMatrix/Saturation.cs

@ -25,10 +25,11 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new saturation of the image. Must be between -100 and 100.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Saturation<TPixel>(this Image<TPixel> source, int amount)
public static IImageProcessingContext<TPixel> Saturation<TPixel>(this IImageProcessingContext<TPixel> source, int amount)
where TPixel : struct, IPixel<TPixel>
{
return Saturation(source, amount, source.Bounds);
source.ApplyProcessor(new SaturationProcessor<TPixel>(amount));
return source;
}
/// <summary>
@ -41,7 +42,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Saturation<TPixel>(this Image<TPixel> source, int amount, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Saturation<TPixel>(this IImageProcessingContext<TPixel> source, int amount, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new SaturationProcessor<TPixel>(amount), rectangle);

13
src/ImageSharp/Processing/ColorMatrix/Sepia.cs

@ -24,11 +24,9 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Sepia<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> Sepia<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return Sepia(source, source.Bounds);
}
=> source.ApplyProcessor(new SepiaProcessor<TPixel>());
/// <summary>
/// Applies sepia toning to the image.
@ -39,11 +37,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Sepia<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Sepia<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new SepiaProcessor<TPixel>(), rectangle);
return source;
}
=> source.ApplyProcessor(new SepiaProcessor<TPixel>(), rectangle);
}
}

23
src/ImageSharp/Processing/Convolution/BoxBlur.cs

@ -17,6 +17,16 @@ namespace ImageSharp
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Applies a box blur to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> BoxBlur<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BoxBlurProcessor<TPixel>(7));
/// <summary>
/// Applies a box blur to the image.
/// </summary>
@ -24,11 +34,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The 'radius' value representing the size of the area to sample.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BoxBlur<TPixel>(this Image<TPixel> source, int radius = 7)
public static IImageProcessingContext<TPixel> BoxBlur<TPixel>(this IImageProcessingContext<TPixel> source, int radius)
where TPixel : struct, IPixel<TPixel>
{
return BoxBlur(source, radius, source.Bounds);
}
=> source.ApplyProcessor(new BoxBlurProcessor<TPixel>(radius));
/// <summary>
/// Applies a box blur to the image.
@ -40,11 +48,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BoxBlur<TPixel>(this Image<TPixel> source, int radius, Rectangle rectangle)
public static IImageProcessingContext<TPixel> BoxBlur<TPixel>(this IImageProcessingContext<TPixel> source, int radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new BoxBlurProcessor<TPixel>(radius), rectangle);
return source;
}
=> source.ApplyProcessor(new BoxBlurProcessor<TPixel>(radius), rectangle);
}
}

91
src/ImageSharp/Processing/Convolution/DetectEdges.cs

@ -25,10 +25,10 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DetectEdges<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return DetectEdges(source, source.Bounds, new SobelProcessor<TPixel> { Grayscale = true });
return DetectEdges(source, new SobelProcessor<TPixel> { Grayscale = true });
}
/// <summary>
@ -41,12 +41,23 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DetectEdges<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return DetectEdges(source, rectangle, new SobelProcessor<TPixel> { Grayscale = true });
}
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetection filter)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, GetProcessor<TPixel>(filter, true));
/// <summary>
/// Detects any edges within the image.
/// </summary>
@ -55,11 +66,9 @@ namespace ImageSharp
/// <param name="filter">The filter for detecting edges.</param>
/// <param name="grayscale">Whether to convert the image to Grayscale first. Defaults to true.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DetectEdges<TPixel>(this Image<TPixel> source, EdgeDetection filter, bool grayscale = true)
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetection filter, bool grayscale)
where TPixel : struct, IPixel<TPixel>
{
return DetectEdges(source, filter, source.Bounds, grayscale);
}
=> DetectEdges(source, GetProcessor<TPixel>(filter, grayscale));
/// <summary>
/// Detects any edges within the image.
@ -72,7 +81,41 @@ namespace ImageSharp
/// </param>
/// <param name="grayscale">Whether to convert the image to Grayscale first. Defaults to true.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DetectEdges<TPixel>(this Image<TPixel> source, EdgeDetection filter, Rectangle rectangle, bool grayscale = true)
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, EdgeDetection filter, Rectangle rectangle, bool grayscale = true)
where TPixel : struct, IPixel<TPixel>
=> DetectEdges(source, rectangle, GetProcessor<TPixel>(filter, grayscale));
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, IEdgeDetectorProcessor<TPixel> filter)
where TPixel : struct, IPixel<TPixel>
{
return source.ApplyProcessor(filter);
}
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DetectEdges<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle, IEdgeDetectorProcessor<TPixel> filter)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(filter, rectangle);
return source;
}
private static IEdgeDetectorProcessor<TPixel> GetProcessor<TPixel>(EdgeDetection filter, bool grayscale)
where TPixel : struct, IPixel<TPixel>
{
IEdgeDetectorProcessor<TPixel> processor;
@ -120,37 +163,7 @@ namespace ImageSharp
break;
}
return DetectEdges(source, rectangle, processor);
}
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DetectEdges<TPixel>(this Image<TPixel> source, IEdgeDetectorProcessor<TPixel> filter)
where TPixel : struct, IPixel<TPixel>
{
return DetectEdges(source, source.Bounds, filter);
}
/// <summary>
/// Detects any edges within the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="filter">The filter for detecting edges.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> DetectEdges<TPixel>(this Image<TPixel> source, Rectangle rectangle, IEdgeDetectorProcessor<TPixel> filter)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(filter, rectangle);
return source;
return processor;
}
}
}

23
src/ImageSharp/Processing/Convolution/GaussianBlur.cs

@ -18,6 +18,16 @@ namespace ImageSharp
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Applies a Gaussian blur to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> GaussianBlur<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GaussianBlurProcessor<TPixel>(3f));
/// <summary>
/// Applies a Gaussian blur to the image.
/// </summary>
@ -25,11 +35,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> GaussianBlur<TPixel>(this Image<TPixel> source, float sigma = 3f)
public static IImageProcessingContext<TPixel> GaussianBlur<TPixel>(this IImageProcessingContext<TPixel> source, float sigma)
where TPixel : struct, IPixel<TPixel>
{
return GaussianBlur(source, sigma, source.Bounds);
}
=> source.ApplyProcessor(new GaussianBlurProcessor<TPixel>(sigma));
/// <summary>
/// Applies a Gaussian blur to the image.
@ -41,11 +49,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> GaussianBlur<TPixel>(this Image<TPixel> source, float sigma, Rectangle rectangle)
public static IImageProcessingContext<TPixel> GaussianBlur<TPixel>(this IImageProcessingContext<TPixel> source, float sigma, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new GaussianBlurProcessor<TPixel>(sigma), rectangle);
return source;
}
=> source.ApplyProcessor(new GaussianBlurProcessor<TPixel>(sigma), rectangle);
}
}

23
src/ImageSharp/Processing/Convolution/GaussianSharpen.cs

@ -18,6 +18,16 @@ namespace ImageSharp
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Applies a Gaussian sharpening filter to the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>(3f));
/// <summary>
/// Applies a Gaussian sharpening filter to the image.
/// </summary>
@ -25,11 +35,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> GaussianSharpen<TPixel>(this Image<TPixel> source, float sigma = 3f)
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source, float sigma)
where TPixel : struct, IPixel<TPixel>
{
return GaussianSharpen(source, sigma, source.Bounds);
}
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>(sigma));
/// <summary>
/// Applies a Gaussian sharpening filter to the image.
@ -41,11 +49,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> GaussianSharpen<TPixel>(this Image<TPixel> source, float sigma, Rectangle rectangle)
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source, float sigma, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>(sigma), rectangle);
return source;
}
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>(sigma), rectangle);
}
}

30
src/ImageSharp/Processing/Delegate.cs

@ -0,0 +1,30 @@
// <copyright file="RotateFlip.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
/// <summary>
/// Extension methods for the <see cref="Image{TPixel}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Queues up an operation that provides access to the mutatable image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="operation">The operations to perform on the source.</param>
/// <returns>returns the current operations class to allow chaining of operations.</returns>
public static IImageProcessingContext<TPixel> Apply<TPixel>(this IImageProcessingContext<TPixel> source, Action<Image<TPixel>> operation)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DelegateProcessor<TPixel>(operation));
}
}

13
src/ImageSharp/Processing/Effects/Alpha.cs

@ -24,11 +24,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="percent">The new opacity of the image. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Alpha<TPixel>(this Image<TPixel> source, float percent)
public static IImageProcessingContext<TPixel> Alpha<TPixel>(this IImageProcessingContext<TPixel> source, float percent)
where TPixel : struct, IPixel<TPixel>
{
return Alpha(source, percent, source.Bounds);
}
=> source.ApplyProcessor(new AlphaProcessor<TPixel>(percent));
/// <summary>
/// Alters the alpha component of the image.
@ -40,11 +38,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Alpha<TPixel>(this Image<TPixel> source, float percent, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Alpha<TPixel>(this IImageProcessingContext<TPixel> source, float percent, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new AlphaProcessor<TPixel>(percent), rectangle);
return source;
}
=> source.ApplyProcessor(new AlphaProcessor<TPixel>(percent), rectangle);
}
}

17
src/ImageSharp/Processing/Effects/BackgroundColor.cs

@ -25,11 +25,9 @@ namespace ImageSharp
/// <param name="color">The color to set as the background.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BackgroundColor<TPixel>(this Image<TPixel> source, TPixel color, GraphicsOptions options)
public static IImageProcessingContext<TPixel> BackgroundColor<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return BackgroundColor(source, color, source.Bounds, options);
}
=> source.ApplyProcessor(new BackgroundColorProcessor<TPixel>(color, options));
/// <summary>
/// Replaces the background color of image with the given one.
@ -42,12 +40,9 @@ namespace ImageSharp
/// </param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BackgroundColor<TPixel>(this Image<TPixel> source, TPixel color, Rectangle rectangle, GraphicsOptions options)
public static IImageProcessingContext<TPixel> BackgroundColor<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new BackgroundColorProcessor<TPixel>(color, options), rectangle);
return source;
}
=> source.ApplyProcessor(new BackgroundColorProcessor<TPixel>(color, options), rectangle);
/// <summary>
/// Replaces the background color of image with the given one.
@ -56,7 +51,7 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the background.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BackgroundColor<TPixel>(this Image<TPixel> source, TPixel color)
public static IImageProcessingContext<TPixel> BackgroundColor<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color)
where TPixel : struct, IPixel<TPixel>
{
return BackgroundColor(source, color, GraphicsOptions.Default);
@ -72,7 +67,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> BackgroundColor<TPixel>(this Image<TPixel> source, TPixel color, Rectangle rectangle)
public static IImageProcessingContext<TPixel> BackgroundColor<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return BackgroundColor(source, color, rectangle, GraphicsOptions.Default);

15
src/ImageSharp/Processing/Effects/Brightness.cs

@ -24,11 +24,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new brightness of the image. Must be between -100 and 100.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Brightness<TPixel>(this Image<TPixel> source, int amount)
where TPixel : struct, IPixel<TPixel>
{
return Brightness(source, amount, source.Bounds);
}
public static IImageProcessingContext<TPixel> Brightness<TPixel>(this IImageProcessingContext<TPixel> source, int amount)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new BrightnessProcessor<TPixel>(amount));
/// <summary>
/// Alters the brightness component of the image.
@ -40,11 +38,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Brightness<TPixel>(this Image<TPixel> source, int amount, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Brightness<TPixel>(this IImageProcessingContext<TPixel> source, int amount, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new BrightnessProcessor<TPixel>(amount), rectangle);
return source;
}
=> source.ApplyProcessor(new BrightnessProcessor<TPixel>(amount), rectangle);
}
}

13
src/ImageSharp/Processing/Effects/Contrast.cs

@ -24,11 +24,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new contrast of the image. Must be between -100 and 100.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Contrast<TPixel>(this Image<TPixel> source, int amount)
public static IImageProcessingContext<TPixel> Contrast<TPixel>(this IImageProcessingContext<TPixel> source, int amount)
where TPixel : struct, IPixel<TPixel>
{
return Contrast(source, amount, source.Bounds);
}
=> source.ApplyProcessor(new ContrastProcessor<TPixel>(amount));
/// <summary>
/// Alters the contrast component of the image.
@ -40,11 +38,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Contrast<TPixel>(this Image<TPixel> source, int amount, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Contrast<TPixel>(this IImageProcessingContext<TPixel> source, int amount, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new ContrastProcessor<TPixel>(amount), rectangle);
return source;
}
=> source.ApplyProcessor(new ContrastProcessor<TPixel>(amount), rectangle);
}
}

13
src/ImageSharp/Processing/Effects/Invert.cs

@ -23,11 +23,9 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Invert<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> Invert<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return Invert(source, source.Bounds);
}
=> source.ApplyProcessor(new InvertProcessor<TPixel>());
/// <summary>
/// Inverts the colors of the image.
@ -38,11 +36,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Invert<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Invert<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
source.ApplyProcessor(new InvertProcessor<TPixel>(), rectangle);
return source;
}
=> source.ApplyProcessor(new InvertProcessor<TPixel>(), rectangle);
}
}

26
src/ImageSharp/Processing/Effects/OilPainting.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> OilPaint<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> OilPaint<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return OilPaint(source, 10, 15);
@ -40,7 +40,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> OilPaint<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> OilPaint<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return OilPaint(source, 10, 15, rectangle);
@ -54,11 +54,9 @@ namespace ImageSharp
/// <param name="levels">The number of intensity levels. Higher values result in a broader range of color intensities forming part of the result image.</param>
/// <param name="brushSize">The number of neighboring pixels used in calculating each individual pixel value.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> OilPaint<TPixel>(this Image<TPixel> source, int levels, int brushSize)
where TPixel : struct, IPixel<TPixel>
{
return OilPaint(source, levels, brushSize, source.Bounds);
}
public static IImageProcessingContext<TPixel> OilPaint<TPixel>(this IImageProcessingContext<TPixel> source, int levels, int brushSize)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new OilPaintingProcessor<TPixel>(levels, brushSize));
/// <summary>
/// Alters the colors of the image recreating an oil painting effect.
@ -71,18 +69,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> OilPaint<TPixel>(this Image<TPixel> source, int levels, int brushSize, Rectangle rectangle)
public static IImageProcessingContext<TPixel> OilPaint<TPixel>(this IImageProcessingContext<TPixel> source, int levels, int brushSize, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
Guard.MustBeGreaterThan(levels, 0, nameof(levels));
if (brushSize <= 0 || brushSize > source.Height || brushSize > source.Width)
{
throw new ArgumentOutOfRangeException(nameof(brushSize));
}
source.ApplyProcessor(new OilPaintingProcessor<TPixel>(levels, brushSize), rectangle);
return source;
}
=> source.ApplyProcessor(new OilPaintingProcessor<TPixel>(levels, brushSize), rectangle);
}
}

28
src/ImageSharp/Processing/Effects/Pixelate.cs

@ -17,6 +17,16 @@ namespace ImageSharp
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Pixelates an image with the given pixel size.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new PixelateProcessor<TPixel>(4));
/// <summary>
/// Pixelates an image with the given pixel size.
/// </summary>
@ -24,11 +34,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="size">The size of the pixels.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Pixelate<TPixel>(this Image<TPixel> source, int size = 4)
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source, int size)
where TPixel : struct, IPixel<TPixel>
{
return Pixelate(source, size, source.Bounds);
}
=> source.ApplyProcessor(new PixelateProcessor<TPixel>(size));
/// <summary>
/// Pixelates an image with the given pixel size.
@ -40,16 +48,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Pixelate<TPixel>(this Image<TPixel> source, int size, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source, int size, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
if (size <= 0 || size > source.Height || size > source.Width)
{
throw new ArgumentOutOfRangeException(nameof(size));
}
source.ApplyProcessor(new PixelateProcessor<TPixel>(size), rectangle);
return source;
}
=> source.ApplyProcessor(new PixelateProcessor<TPixel>(size), rectangle);
}
}

79
src/ImageSharp/Processing/Overlays/Glow.cs

@ -21,7 +21,7 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, GraphicsOptions.Default);
@ -34,7 +34,7 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the glow.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, TPixel color)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, color, GraphicsOptions.Default);
@ -47,7 +47,7 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="radius">The the radius.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, float radius)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, float radius)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, radius, GraphicsOptions.Default);
@ -62,11 +62,9 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, rectangle, GraphicsOptions.Default);
}
=> source.Glow(rectangle, GraphicsOptions.Default);
/// <summary>
/// Applies a radial glow effect to an image.
@ -79,11 +77,9 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, TPixel color, float radius, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float radius, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, color, radius, rectangle, GraphicsOptions.Default);
}
=> source.Glow(color, ValueSize.Absolute(radius), rectangle, GraphicsOptions.Default);
/// <summary>
/// Applies a radial glow effect to an image.
@ -92,11 +88,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, NamedColors<TPixel>.Black, source.Bounds.Width * .5F, source.Bounds, options);
}
=> source.Glow(NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(0.5f), options);
/// <summary>
/// Applies a radial glow effect to an image.
@ -106,11 +100,9 @@ namespace ImageSharp
/// <param name="color">The color to set as the glow.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, TPixel color, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, color, source.Bounds.Width * .5F, source.Bounds, options);
}
=> source.Glow(color, ValueSize.PercentageOfWidth(0.5f), options);
/// <summary>
/// Applies a radial glow effect to an image.
@ -120,11 +112,9 @@ namespace ImageSharp
/// <param name="radius">The the radius.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, float radius, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, float radius, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, NamedColors<TPixel>.Black, radius, source.Bounds, options);
}
=> source.Glow(NamedColors<TPixel>.Black, ValueSize.Absolute(radius), options);
/// <summary>
/// Applies a radial glow effect to an image.
@ -136,11 +126,9 @@ namespace ImageSharp
/// </param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, Rectangle rectangle, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Glow(source, NamedColors<TPixel>.Black, 0, rectangle, options);
}
=> source.Glow(NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(0.5f), rectangle, options);
/// <summary>
/// Applies a radial glow effect to an image.
@ -154,12 +142,37 @@ namespace ImageSharp
/// </param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Glow<TPixel>(this Image<TPixel> source, TPixel color, float radius, Rectangle rectangle, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float radius, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
var processor = new GlowProcessor<TPixel>(color, options) { Radius = radius, };
source.ApplyProcessor(processor, rectangle);
return source;
}
=> source.Glow(color, ValueSize.Absolute(radius), rectangle, options);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the glow.</param>
/// <param name="radius">The the radius.</param>
/// <param name="rectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
private static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, ValueSize radius, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GlowProcessor<TPixel>(color, radius, options), rectangle);
/// <summary>
/// Applies a radial glow effect to an image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the glow.</param>
/// <param name="radius">The the radius.</param>
/// <param name="options">The options effecting things like blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
private static IImageProcessingContext<TPixel> Glow<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, ValueSize radius, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new GlowProcessor<TPixel>(color, radius, options));
}
}

54
src/ImageSharp/Processing/Overlays/Vignette.cs

@ -21,7 +21,7 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, GraphicsOptions.Default);
@ -34,7 +34,7 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color to set as the vignette.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, TPixel color)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, color, GraphicsOptions.Default);
@ -48,7 +48,7 @@ namespace ImageSharp
/// <param name="radiusX">The the x-radius.</param>
/// <param name="radiusY">The the y-radius.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, float radiusX, float radiusY)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, float radiusX, float radiusY)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, radiusX, radiusY, GraphicsOptions.Default);
@ -63,7 +63,7 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, rectangle, GraphicsOptions.Default);
@ -81,11 +81,9 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, TPixel color, float radiusX, float radiusY, Rectangle rectangle)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float radiusX, float radiusY, Rectangle rectangle)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, color, radiusX, radiusY, rectangle, GraphicsOptions.Default);
}
=> source.Vignette(color, radiusX, radiusY, rectangle, GraphicsOptions.Default);
/// <summary>
/// Applies a radial vignette effect to an image.
@ -94,11 +92,9 @@ namespace ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, NamedColors<TPixel>.Black, source.Bounds.Width * .5F, source.Bounds.Height * .5F, source.Bounds, options);
}
=> source.VignetteInternal(NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(.5f), ValueSize.PercentageOfHeight(.5f), options);
/// <summary>
/// Applies a radial vignette effect to an image.
@ -108,11 +104,9 @@ namespace ImageSharp
/// <param name="color">The color to set as the vignette.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, TPixel color, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, color, source.Bounds.Width * .5F, source.Bounds.Height * .5F, source.Bounds, options);
}
=> source.VignetteInternal(color, ValueSize.PercentageOfWidth(.5f), ValueSize.PercentageOfHeight(.5f), options);
/// <summary>
/// Applies a radial vignette effect to an image.
@ -123,11 +117,9 @@ namespace ImageSharp
/// <param name="radiusY">The the y-radius.</param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, float radiusX, float radiusY, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, float radiusX, float radiusY, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, NamedColors<TPixel>.Black, radiusX, radiusY, source.Bounds, options);
}
=> source.VignetteInternal(NamedColors<TPixel>.Black, radiusX, radiusY, options);
/// <summary>
/// Applies a radial vignette effect to an image.
@ -139,11 +131,9 @@ namespace ImageSharp
/// </param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, Rectangle rectangle, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return Vignette(source, NamedColors<TPixel>.Black, 0, 0, rectangle, options);
}
=> source.VignetteInternal(NamedColors<TPixel>.Black, ValueSize.PercentageOfWidth(.5f), ValueSize.PercentageOfHeight(.5f), rectangle, options);
/// <summary>
/// Applies a radial vignette effect to an image.
@ -158,12 +148,16 @@ namespace ImageSharp
/// </param>
/// <param name="options">The options effecting pixel blending.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Vignette<TPixel>(this Image<TPixel> source, TPixel color, float radiusX, float radiusY, Rectangle rectangle, GraphicsOptions options)
public static IImageProcessingContext<TPixel> Vignette<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, float radiusX, float radiusY, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
var processor = new VignetteProcessor<TPixel>(color, options) { RadiusX = radiusX, RadiusY = radiusY };
source.ApplyProcessor(processor, rectangle);
return source;
}
=> source.VignetteInternal(color, radiusX, radiusY, rectangle, options);
private static IImageProcessingContext<TPixel> VignetteInternal<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, ValueSize radiusX, ValueSize radiusY, Rectangle rectangle, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new VignetteProcessor<TPixel>(color, radiusX, radiusY, options), rectangle);
private static IImageProcessingContext<TPixel> VignetteInternal<TPixel>(this IImageProcessingContext<TPixel> source, TPixel color, ValueSize radiusX, ValueSize radiusY, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new VignetteProcessor<TPixel>(color, radiusX, radiusY, options));
}
}

166
src/ImageSharp/Processing/Processors/CloningImageProcessor.cs

@ -0,0 +1,166 @@
// <copyright file="CloneingImageProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Processing
{
using System;
using System.Threading.Tasks;
using ImageSharp.PixelFormats;
using SixLabors.Primitives;
/// <summary>
/// Allows the application of processors to images.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract class CloningImageProcessor<TPixel> : IImageProcessor<TPixel>, ICloningImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <inheritdoc/>
public virtual ParallelOptions ParallelOptions { get; set; }
/// <inheritdoc/>
public virtual bool Compand { get; set; } = false;
/// <inheritdoc/>
public Image<TPixel> CloneAndApply(Image<TPixel> source, Rectangle sourceRectangle)
{
if (this.ParallelOptions == null)
{
this.ParallelOptions = source.Configuration.ParallelOptions;
}
try
{
Image<TPixel> clone = this.CreateDestination(source, sourceRectangle);
if (clone.Frames.Count != source.Frames.Count)
{
throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
}
this.BeforeImageApply(source, clone, sourceRectangle);
this.BeforeApply(source, clone, sourceRectangle);
this.OnApply(source, clone, sourceRectangle);
this.AfterApply(source, clone, sourceRectangle);
for (int i = 0; i < source.Frames.Count; i++)
{
ImageFrame<TPixel> sourceFrame = source.Frames[i];
ImageFrame<TPixel> clonedFrame = clone.Frames[i];
this.BeforeApply(sourceFrame, clonedFrame, sourceRectangle);
this.OnApply(sourceFrame, clonedFrame, sourceRectangle);
this.AfterApply(sourceFrame, clonedFrame, sourceRectangle);
}
this.AfterImageApply(source, clone, sourceRectangle);
return clone;
}
#if DEBUG
catch (Exception)
{
throw;
#else
catch (Exception ex)
{
throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex);
#endif
}
}
/// <inheritdoc/>
public void Apply(Image<TPixel> source, Rectangle sourceRectangle)
{
using (Image<TPixel> cloned = this.CloneAndApply(source, sourceRectangle))
{
// we now need to move the pixel data/size data from one image base to another
if (cloned.Frames.Count != source.Frames.Count)
{
throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. The processor changed the number of frames.");
}
source.SwapPixelsData(cloned);
for (int i = 0; i < source.Frames.Count; i++)
{
source.Frames[i].SwapPixelsData(cloned.Frames[i]);
}
}
}
/// <summary>
/// Generates the clone of the source image that operatinos should be applied to.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle">The source rectangle.</param>
/// <returns>The cloned image.</returns>
protected virtual Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle)
{
return source.Clone();
}
/// <summary>
/// This method is called before the process is applied to prepare the processor.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="destination">The cloned/destination image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void BeforeImageApply(Image<TPixel> source, Image<TPixel> destination, Rectangle sourceRectangle)
{
}
/// <summary>
/// This method is called before the process is applied to prepare the processor.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="destination">The cloned/destination image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void BeforeApply(ImageBase<TPixel> source, ImageBase<TPixel> destination, Rectangle sourceRectangle)
{
}
/// <summary>
/// Applies the process to the specified portion of the specified <see cref="ImageBase{TPixel}"/> at the specified location
/// and with the specified size.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="destination">The cloned/destination image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected abstract void OnApply(ImageBase<TPixel> source, ImageBase<TPixel> destination, Rectangle sourceRectangle);
/// <summary>
/// This method is called after the process is applied to prepare the processor.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="destination">The cloned/destination image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void AfterApply(ImageBase<TPixel> source, ImageBase<TPixel> destination, Rectangle sourceRectangle)
{
}
/// <summary>
/// This method is called after the process is applied to prepare the processor.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="destination">The cloned/destination image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void AfterImageApply(Image<TPixel> source, Image<TPixel> destination, Rectangle sourceRectangle)
{
}
}
}

2
src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs

@ -53,7 +53,7 @@ namespace ImageSharp.Processing.Processors
protected override void AfterApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
{
new VignetteProcessor<TPixel>(veryDarkOrange, this.options).Apply(source, sourceRectangle);
new GlowProcessor<TPixel>(lightOrange, this.options) { Radius = source.Width / 4F }.Apply(source, sourceRectangle);
new GlowProcessor<TPixel>(lightOrange, source.Width / 4F, this.options).Apply(source, sourceRectangle);
}
}
}

6
src/ImageSharp/Processing/Processors/ColorMatrix/SaturationProcessor.cs

@ -26,6 +26,7 @@ namespace ImageSharp.Processing.Processors
/// </exception>
public SaturationProcessor(int saturation)
{
this.Amount = saturation;
Guard.MustBeBetweenOrEqualTo(saturation, -100, 100, nameof(saturation));
float saturationFactor = saturation / 100F;
@ -58,6 +59,11 @@ namespace ImageSharp.Processing.Processors
this.Matrix = matrix4X4;
}
/// <summary>
/// Gets the amount to apply.
/// </summary>
public int Amount { get; }
/// <inheritdoc/>
public override Matrix4x4 Matrix { get; }
}

6
src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs

@ -31,11 +31,17 @@ namespace ImageSharp.Processing.Processors
/// </param>
public BoxBlurProcessor(int radius = 7)
{
this.Radius = radius;
this.kernelSize = (radius * 2) + 1;
this.KernelX = this.CreateBoxKernel(true);
this.KernelY = this.CreateBoxKernel(false);
}
/// <summary>
/// Gets the Radius
/// </summary>
public int Radius { get; }
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>

2
src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs

@ -50,7 +50,7 @@ namespace ImageSharp.Processing.Processors
using (var firstPassPixels = new PixelAccessor<TPixel>(width, height))
using (PixelAccessor<TPixel> sourcePixels = source.Lock())
{
this.ApplyConvolution(firstPassPixels, sourcePixels, source.Bounds, this.KernelX);
this.ApplyConvolution(firstPassPixels, sourcePixels, source.Bounds(), this.KernelX);
this.ApplyConvolution(sourcePixels, firstPassPixels, sourceRectangle, this.KernelY);
}
}

4
src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs

@ -89,7 +89,7 @@ namespace ImageSharp.Processing.Processors
int maxY = Math.Min(source.Height, endY);
// we need a clean copy for each pass to start from
using (ImageBase<TPixel> cleanCopy = new Image<TPixel>(source))
using (ImageBase<TPixel> cleanCopy = source.Clone())
{
new ConvolutionProcessor<TPixel>(kernels[0]).Apply(source, sourceRectangle);
@ -116,7 +116,7 @@ namespace ImageSharp.Processing.Processors
// ReSharper disable once ForCanBeConvertedToForeach
for (int i = 1; i < kernels.Length; i++)
{
using (ImageBase<TPixel> pass = new Image<TPixel>(cleanCopy))
using (ImageBase<TPixel> pass = cleanCopy.Clone())
{
new ConvolutionProcessor<TPixel>(kernels[i]).Apply(pass, sourceRectangle);

5
src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs

@ -72,6 +72,11 @@ namespace ImageSharp.Processing.Processors
this.KernelY = this.CreateGaussianKernel(false);
}
/// <summary>
/// Gets the sigma
/// </summary>
public float Sigma => this.sigma;
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>

5
src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs

@ -74,6 +74,11 @@ namespace ImageSharp.Processing.Processors
this.KernelY = this.CreateGaussianKernel(false);
}
/// <summary>
/// Gets the sigma
/// </summary>
public float Sigma => this.sigma;
/// <summary>
/// Gets the horizontal gradient operator.
/// </summary>

48
src/ImageSharp/Processing/Processors/DelegateProcessor.cs

@ -0,0 +1,48 @@
// <copyright file="DelegateProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Processing
{
using System;
using ImageSharp.PixelFormats;
using SixLabors.Primitives;
/// <summary>
/// Allows the application of processors to images.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class DelegateProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Action<Image<TPixel>> action;
/// <summary>
/// Initializes a new instance of the <see cref="DelegateProcessor{TPixel}"/> class.
/// </summary>
/// <param name="action">The action.</param>
public DelegateProcessor(Action<Image<TPixel>> action)
{
this.action = action;
}
/// <summary>
/// Gets the action that will be applied to the image.
/// </summary>
internal Action<Image<TPixel>> Action => this.action;
/// <inheritdoc/>
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
this.action?.Invoke(source);
}
/// <inheritdoc/>
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
{
// NOP, we did all we wanted to do inside BeforeImageApply
}
}
}

5
src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs

@ -32,6 +32,11 @@ namespace ImageSharp.Processing.Processors
this.options = options;
}
/// <summary>
/// Gets the Graphics options to alter how processor is applied.
/// </summary>
public GraphicsOptions GraphicsOptions => this.options;
/// <summary>
/// Gets the background color value.
/// </summary>

5
src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs

@ -51,6 +51,11 @@ namespace ImageSharp.Processing.Processors
/// <inheritdoc/>
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
{
if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width)
{
throw new ArgumentOutOfRangeException(nameof(this.BrushSize));
}
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;

13
src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs

@ -29,23 +29,28 @@ namespace ImageSharp.Processing.Processors
public PixelateProcessor(int size)
{
Guard.MustBeGreaterThan(size, 0, nameof(size));
this.Value = size;
this.Size = size;
}
/// <summary>
/// Gets or the pixel size.
/// </summary>
public int Value { get; }
public int Size { get; }
/// <inheritdoc/>
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
{
if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width)
{
throw new ArgumentOutOfRangeException(nameof(this.Size));
}
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int size = this.Value;
int offset = this.Value / 2;
int size = this.Size;
int offset = this.Size / 2;
// Align start/end positions.
int minX = Math.Max(0, startX);

66
src/ImageSharp/Processing/ImageProcessor.cs → src/ImageSharp/Processing/Processors/ImageProcessor.cs

@ -25,7 +25,7 @@ namespace ImageSharp.Processing
public virtual bool Compand { get; set; } = false;
/// <inheritdoc/>
public void Apply(ImageBase<TPixel> source, Rectangle sourceRectangle)
public void Apply(Image<TPixel> source, Rectangle sourceRectangle)
{
if (this.ParallelOptions == null)
{
@ -34,10 +34,50 @@ namespace ImageSharp.Processing
try
{
this.BeforeApply(source, sourceRectangle);
this.BeforeImageApply(source, sourceRectangle);
this.BeforeApply(source, sourceRectangle);
this.OnApply(source, sourceRectangle);
this.AfterApply(source, sourceRectangle);
foreach (ImageFrame<TPixel> sourceFrame in source.Frames)
{
this.BeforeApply(sourceFrame, sourceRectangle);
this.OnApply(sourceFrame, sourceRectangle);
this.AfterApply(sourceFrame, sourceRectangle);
}
this.AfterImageApply(source, sourceRectangle);
}
#if DEBUG
catch (Exception)
{
throw;
#else
catch (Exception ex)
{
throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex);
#endif
}
}
/// <summary>
/// Applies the processor to just a single ImageBase
/// </summary>
/// <param name="source">the source image</param>
/// <param name="sourceRectangle">the target</param>
public void Apply(ImageBase<TPixel> source, Rectangle sourceRectangle)
{
if (this.ParallelOptions == null)
{
this.ParallelOptions = source.Configuration.ParallelOptions;
}
try
{
this.BeforeApply(source, sourceRectangle);
this.OnApply(source, sourceRectangle);
this.AfterApply(source, sourceRectangle);
}
#if DEBUG
@ -52,6 +92,17 @@ namespace ImageSharp.Processing
}
}
/// <summary>
/// This method is called before the process is applied to prepare the processor.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
}
/// <summary>
/// This method is called before the process is applied to prepare the processor.
/// </summary>
@ -83,5 +134,16 @@ namespace ImageSharp.Processing
protected virtual void AfterApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
{
}
/// <summary>
/// This method is called after the process is applied to prepare the processor.
/// </summary>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
protected virtual void AfterImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
}
}
}

16
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs

@ -27,14 +27,21 @@ namespace ImageSharp.Processing.Processors
/// Initializes a new instance of the <see cref="GlowProcessor{TPixel}" /> class.
/// </summary>
/// <param name="color">The color or the glow.</param>
/// <param name="radius">The radius of the glow.</param>
/// <param name="options">The options effecting blending and composition.</param>
public GlowProcessor(TPixel color, GraphicsOptions options)
public GlowProcessor(TPixel color, ValueSize radius, GraphicsOptions options)
{
this.options = options;
this.GlowColor = color;
this.Radius = radius;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(this.options.BlenderMode);
}
/// <summary>
/// Gets the Graphics options to alter how processor is applied.
/// </summary>
public GraphicsOptions GraphicsOptions => this.options;
/// <summary>
/// Gets or sets the glow color to apply.
/// </summary>
@ -43,7 +50,7 @@ namespace ImageSharp.Processing.Processors
/// <summary>
/// Gets or sets the the radius.
/// </summary>
public float Radius { get; set; }
public ValueSize Radius { get; set; }
/// <inheritdoc/>
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
@ -54,7 +61,10 @@ namespace ImageSharp.Processing.Processors
int endX = sourceRectangle.Right;
TPixel glowColor = this.GlowColor;
Vector2 centre = Rectangle.Center(sourceRectangle);
float maxDistance = this.Radius > 0 ? MathF.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
var finalRadius = this.Radius.Calculate(source.Size());
float maxDistance = finalRadius > 0 ? MathF.Min(finalRadius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
// Align start/end positions.
int minX = Math.Max(0, startX);

33
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs

@ -27,15 +27,35 @@ namespace ImageSharp.Processing.Processors
/// Initializes a new instance of the <see cref="VignetteProcessor{TPixel}" /> class.
/// </summary>
/// <param name="color">The color of the vignette.</param>
/// <param name="radiusX">The x-radius.</param>
/// <param name="radiusY">The y-radius.</param>
/// <param name="options">The options effecting blending and composition.</param>
public VignetteProcessor(TPixel color, GraphicsOptions options)
public VignetteProcessor(TPixel color, ValueSize radiusX, ValueSize radiusY, GraphicsOptions options)
{
this.VignetteColor = color;
this.RadiusX = radiusX;
this.RadiusY = radiusY;
this.options = options;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(this.options.BlenderMode);
}
/// <summary>
/// Initializes a new instance of the <see cref="VignetteProcessor{TPixel}" /> class.
/// </summary>
/// <param name="color">The color of the vignette.</param>
/// <param name="options">The options effecting blending and composition.</param>
public VignetteProcessor(TPixel color, GraphicsOptions options)
{
this.VignetteColor = color;
this.options = options;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(this.options.BlenderMode);
}
/// <summary>
/// Gets the Graphics options to alter how processor is applied.
/// </summary>
public GraphicsOptions GraphicsOptions => this.options;
/// <summary>
/// Gets or sets the vignette color to apply.
/// </summary>
@ -44,12 +64,12 @@ namespace ImageSharp.Processing.Processors
/// <summary>
/// Gets or sets the the x-radius.
/// </summary>
public float RadiusX { get; set; }
public ValueSize RadiusX { get; set; }
/// <summary>
/// Gets or sets the the y-radius.
/// </summary>
public float RadiusY { get; set; }
public ValueSize RadiusY { get; set; }
/// <inheritdoc/>
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
@ -60,8 +80,11 @@ namespace ImageSharp.Processing.Processors
int endX = sourceRectangle.Right;
TPixel vignetteColor = this.VignetteColor;
Vector2 centre = Rectangle.Center(sourceRectangle);
float rX = this.RadiusX > 0 ? MathF.Min(this.RadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
float rY = this.RadiusY > 0 ? MathF.Min(this.RadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F;
var finalradiusX = this.RadiusX.Calculate(source.Size());
var finalradiusY = this.RadiusY.Calculate(source.Size());
float rX = finalradiusX > 0 ? MathF.Min(finalradiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
float rY = finalradiusY > 0 ? MathF.Min(finalradiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F;
float maxDistance = MathF.Sqrt((rX * rX) + (rY * rY));
// Align start/end positions.

112
src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs

@ -0,0 +1,112 @@
// <copyright file="FlipProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Processing.Processors
{
using System;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using SixLabors.Primitives;
/// <summary>
/// Adjusts an image so that its orientation is suitable for viewing. Adjustments are based on EXIF metadata embedded in the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class AutoRotateProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="AutoRotateProcessor{TPixel}"/> class.
/// </summary>
public AutoRotateProcessor()
{
}
/// <inheritdoc/>
protected override void OnApply(ImageBase<TPixel> sourceBase, Rectangle sourceRectangle)
{
// can only apply to the origional image
var source = sourceBase as Image<TPixel>;
if (source != null)
{
Orientation orientation = GetExifOrientation(source);
switch (orientation)
{
case Orientation.TopRight:
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle);
break;
case Orientation.BottomRight:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate180, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.BottomLeft:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle);
break;
case Orientation.LeftTop:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle);
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle);
break;
case Orientation.RightTop:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.RightBottom:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.LeftBottom:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.Unknown:
case Orientation.TopLeft:
default:
break;
}
}
}
/// <summary>
/// Returns the current EXIF orientation
/// </summary>
/// <param name="source">The image to auto rotate.</param>
/// <returns>The <see cref="Orientation"/></returns>
private static Orientation GetExifOrientation(Image<TPixel> source)
{
if (source.MetaData.ExifProfile == null)
{
return Orientation.Unknown;
}
ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation);
if (value == null)
{
return Orientation.Unknown;
}
Orientation orientation;
if (value.DataType == ExifDataType.Short)
{
orientation = (Orientation)value.Value;
}
else
{
orientation = (Orientation)Convert.ToUInt16(value.Value);
source.MetaData.ExifProfile.RemoveValue(ExifTag.Orientation);
}
source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft);
return orientation;
}
}
}

8
src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs

@ -28,24 +28,24 @@ namespace ImageSharp.Processing.Processors
public EntropyCropProcessor(float threshold)
{
Guard.MustBeBetweenOrEqualTo(threshold, 0, 1, nameof(threshold));
this.Value = threshold;
this.Threshold = threshold;
}
/// <summary>
/// Gets the threshold value.
/// </summary>
public float Value { get; }
public float Threshold { get; }
/// <inheritdoc/>
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
{
using (ImageBase<TPixel> temp = new Image<TPixel>(source))
using (ImageBase<TPixel> temp = source.Clone())
{
// Detect the edges.
new SobelProcessor<TPixel>().Apply(temp, sourceRectangle);
// Apply threshold binarization filter.
new BinaryThresholdProcessor<TPixel>(this.Value).Apply(temp, sourceRectangle);
new BinaryThresholdProcessor<TPixel>(this.Threshold).Apply(temp, sourceRectangle);
// Search for the first white pixels
Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0);

20
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs

@ -16,7 +16,7 @@ namespace ImageSharp.Processing.Processors
/// Adapted from <see href="http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/filter_rcg.c"/>
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal abstract partial class ResamplingWeightedProcessor<TPixel> : ImageProcessor<TPixel>
internal abstract partial class ResamplingWeightedProcessor<TPixel> : CloningImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
@ -46,19 +46,19 @@ namespace ImageSharp.Processing.Processors
public IResampler Sampler { get; }
/// <summary>
/// Gets the width.
/// Gets or sets the width.
/// </summary>
public int Width { get; }
public int Width { get; protected set; }
/// <summary>
/// Gets the height.
/// Gets or sets the height.
/// </summary>
public int Height { get; }
public int Height { get; protected set; }
/// <summary>
/// Gets the resize rectangle.
/// Gets or sets the resize rectangle.
/// </summary>
public Rectangle ResizeRectangle { get; }
public Rectangle ResizeRectangle { get; protected set; }
/// <summary>
/// Gets or sets the horizontal weights.
@ -140,7 +140,7 @@ namespace ImageSharp.Processing.Processors
}
/// <inheritdoc/>
protected override void BeforeApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
protected override void BeforeApply(ImageBase<TPixel> source, ImageBase<TPixel> destination, Rectangle sourceRectangle)
{
if (!(this.Sampler is NearestNeighborResampler))
{
@ -155,9 +155,9 @@ namespace ImageSharp.Processing.Processors
}
/// <inheritdoc />
protected override void AfterApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
protected override void AfterApply(ImageBase<TPixel> source, ImageBase<TPixel> destination, Rectangle sourceRectangle)
{
base.AfterApply(source, sourceRectangle);
base.AfterApply(source, destination, sourceRectangle);
this.HorizontalWeights?.Dispose();
this.HorizontalWeights = null;
this.VerticalWeights?.Dispose();

180
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -46,11 +46,32 @@ namespace ImageSharp.Processing.Processors
}
/// <inheritdoc/>
protected override unsafe void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle)
protected override Image<TPixel> CreateDestination(Image<TPixel> source, Rectangle sourceRectangle)
{
// We will always be creating the clone even for mutate because thats the way this base processor works
// ------------
// For resize we know we are going to populate every pixel with fresh data and we want a different target size so
// let's manually clone an empty set of images at the correct target and then have the base class processs them in turn.
var image = new Image<TPixel>(source.Configuration, this.Width, this.Height, source.MetaData.Clone());
// Now 'clone' the ImageFrames
foreach (ImageFrame<TPixel> sourceFrame in source.Frames)
{
var targetFrame = new ImageFrame<TPixel>(sourceFrame.Configuration, this.Width, this.Height, sourceFrame.MetaData.Clone());
image.Frames.Add(targetFrame);
}
return image;
}
/// <inheritdoc/>
protected override unsafe void OnApply(ImageBase<TPixel> source, ImageBase<TPixel> cloned, Rectangle sourceRectangle)
{
// Jump out, we'll deal with that later.
if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle)
if (source.Width == cloned.Width && source.Height == cloned.Height && sourceRectangle == this.ResizeRectangle)
{
// the cloned will be blank here copy all the pixel data over
source.Pixels.CopyTo(cloned.Pixels);
return;
}
@ -74,113 +95,102 @@ namespace ImageSharp.Processing.Processors
float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;
using (var targetPixels = new PixelAccessor<TPixel>(width, height))
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Y coordinates of source points
Span<TPixel> sourceRow = source.GetRowSpan((int)(((y - startY) * heightFactor) + sourceY));
Span<TPixel> targetRow = cloned.GetRowSpan(y);
for (int x = minX; x < maxX; x++)
{
// Y coordinates of source points
Span<TPixel> sourceRow = source.GetRowSpan((int)(((y - startY) * heightFactor) + sourceY));
Span<TPixel> targetRow = targetPixels.GetRowSpan(y);
// X coordinates of source points
targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)];
}
});
for (int x = minX; x < maxX; x++)
{
// X coordinates of source points
targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)];
}
});
// Break out now.
source.SwapPixelsBuffers(targetPixels);
return;
}
return;
}
// Interpolate the image using the calculated weights.
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
// First process the columns. Since we are not using multiple threads startY and endY
// are the upper and lower bounds of the source rectangle.
// TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed!
using (var targetPixels = new PixelAccessor<TPixel>(width, height))
using (var firstPassPixels = new Buffer2D<Vector4>(width, source.Height))
{
using (var firstPassPixels = new Buffer2D<Vector4>(width, source.Height))
{
firstPassPixels.Clear();
Parallel.For(
0,
sourceRectangle.Bottom,
this.ParallelOptions,
y =>
firstPassPixels.Clear();
Parallel.For(
0,
sourceRectangle.Bottom,
this.ParallelOptions,
y =>
{
// TODO: Without Parallel.For() this buffer object could be reused:
using (var tempRowBuffer = new Buffer<Vector4>(source.Width))
{
// TODO: Without Parallel.For() this buffer object could be reused:
using (var tempRowBuffer = new Buffer<Vector4>(source.Width))
{
Span<Vector4> firstPassRow = firstPassPixels.GetRowSpan(y);
Span<TPixel> sourceRow = source.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(sourceRow, tempRowBuffer, sourceRow.Length);
Span<Vector4> firstPassRow = firstPassPixels.GetRowSpan(y);
Span<TPixel> sourceRow = source.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToVector4(sourceRow, tempRowBuffer, sourceRow.Length);
if (this.Compand)
if (this.Compand)
{
for (int x = minX; x < maxX; x++)
{
for (int x = minX; x < maxX; x++)
{
WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
firstPassRow[x] = window.ComputeExpandedWeightedRowSum(tempRowBuffer, sourceX);
}
WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
firstPassRow[x] = window.ComputeExpandedWeightedRowSum(tempRowBuffer, sourceX);
}
else
}
else
{
for (int x = minX; x < maxX; x++)
{
for (int x = minX; x < maxX; x++)
{
WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
firstPassRow[x] = window.ComputeWeightedRowSum(tempRowBuffer, sourceX);
}
WeightsWindow window = this.HorizontalWeights.Weights[x - startX];
firstPassRow[x] = window.ComputeWeightedRowSum(tempRowBuffer, sourceX);
}
}
});
// Now process the rows.
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Ensure offsets are normalised for cropping and padding.
WeightsWindow window = this.VerticalWeights.Weights[y - startY];
Span<TPixel> targetRow = targetPixels.GetRowSpan(y);
}
});
if (this.Compand)
// Now process the rows.
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
// Ensure offsets are normalised for cropping and padding.
WeightsWindow window = this.VerticalWeights.Weights[y - startY];
Span<TPixel> targetRow = cloned.GetRowSpan(y);
if (this.Compand)
{
for (int x = 0; x < width; x++)
{
for (int x = 0; x < width; x++)
{
// Destination color components
Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x, sourceY);
destination = destination.Compress();
// Destination color components
Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x, sourceY);
destination = destination.Compress();
ref TPixel pixel = ref targetRow[x];
pixel.PackFromVector4(destination);
}
ref TPixel pixel = ref targetRow[x];
pixel.PackFromVector4(destination);
}
else
}
else
{
for (int x = 0; x < width; x++)
{
for (int x = 0; x < width; x++)
{
// Destination color components
Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x, sourceY);
// Destination color components
Vector4 destination = window.ComputeWeightedColumnSum(firstPassPixels, x, sourceY);
ref TPixel pixel = ref targetRow[x];
pixel.PackFromVector4(destination);
}
ref TPixel pixel = ref targetRow[x];
pixel.PackFromVector4(destination);
}
});
}
source.SwapPixelsBuffers(targetPixels);
}
});
}
}
}

3
src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs

@ -45,6 +45,7 @@ namespace ImageSharp.Processing.Processors
int height = this.CanvasRectangle.Height;
int width = this.CanvasRectangle.Width;
Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix);
Rectangle sourceBounds = source.Bounds();
using (var targetPixels = new PixelAccessor<TPixel>(width, height))
{
@ -60,7 +61,7 @@ namespace ImageSharp.Processing.Processors
{
var transformedPoint = Point.Rotate(new Point(x, y), matrix);
if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
if (sourceBounds.Contains(transformedPoint.X, transformedPoint.Y))
{
targetRow[x] = source[transformedPoint.X, transformedPoint.Y];
}

3
src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs

@ -45,6 +45,7 @@ namespace ImageSharp.Processing.Processors
int height = this.CanvasRectangle.Height;
int width = this.CanvasRectangle.Width;
Matrix3x2 matrix = this.GetCenteredMatrix(source, this.processMatrix);
Rectangle sourceBounds = source.Bounds();
using (var targetPixels = new PixelAccessor<TPixel>(width, height))
{
@ -60,7 +61,7 @@ namespace ImageSharp.Processing.Processors
{
var transformedPoint = Point.Skew(new Point(x, y), matrix);
if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
if (sourceBounds.Contains(transformedPoint.X, transformedPoint.Y))
{
targetRow[x] = source[transformedPoint.X, transformedPoint.Y];
}

73
src/ImageSharp/Processing/Transforms/AutoOrient.cs

@ -21,77 +21,8 @@ namespace ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to auto rotate.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> AutoOrient<TPixel>(this Image<TPixel> source)
public static IImageProcessingContext<TPixel> AutoOrient<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
Orientation orientation = GetExifOrientation(source);
switch (orientation)
{
case Orientation.TopRight:
return source.Flip(FlipType.Horizontal);
case Orientation.BottomRight:
return source.Rotate(RotateType.Rotate180);
case Orientation.BottomLeft:
return source.Flip(FlipType.Vertical);
case Orientation.LeftTop:
return source.Rotate(RotateType.Rotate90)
.Flip(FlipType.Horizontal);
case Orientation.RightTop:
return source.Rotate(RotateType.Rotate90);
case Orientation.RightBottom:
return source.Flip(FlipType.Vertical)
.Rotate(RotateType.Rotate270);
case Orientation.LeftBottom:
return source.Rotate(RotateType.Rotate270);
case Orientation.Unknown:
case Orientation.TopLeft:
default:
return source;
}
}
/// <summary>
/// Returns the current EXIF orientation
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to auto rotate.</param>
/// <returns>The <see cref="Orientation"/></returns>
private static Orientation GetExifOrientation<TPixel>(Image<TPixel> source)
where TPixel : struct, IPixel<TPixel>
{
if (source.MetaData.ExifProfile == null)
{
return Orientation.Unknown;
}
ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation);
if (value == null)
{
return Orientation.Unknown;
}
Orientation orientation;
if (value.DataType == ExifDataType.Short)
{
orientation = (Orientation)value.Value;
}
else
{
orientation = (Orientation)Convert.ToUInt16(value.Value);
source.MetaData.ExifProfile.RemoveValue(ExifTag.Orientation);
}
source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft);
return orientation;
}
=> source.ApplyProcessor(new Processing.Processors.AutoRotateProcessor<TPixel>());
}
}

15
src/ImageSharp/Processing/Transforms/Crop.cs

@ -25,11 +25,9 @@ namespace ImageSharp
/// <param name="width">The target image width.</param>
/// <param name="height">The target image height.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> Crop<TPixel>(this Image<TPixel> source, int width, int height)
public static IImageProcessingContext<TPixel> Crop<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height)
where TPixel : struct, IPixel<TPixel>
{
return Crop(source, new Rectangle(0, 0, width, height));
}
=> Crop(source, new Rectangle(0, 0, width, height));
/// <summary>
/// Crops an image to the given rectangle.
@ -40,13 +38,8 @@ namespace ImageSharp
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to retain.
/// </param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> Crop<TPixel>(this Image<TPixel> source, Rectangle cropRectangle)
public static IImageProcessingContext<TPixel> Crop<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle cropRectangle)
where TPixel : struct, IPixel<TPixel>
{
CropProcessor<TPixel> processor = new CropProcessor<TPixel>(cropRectangle);
source.ApplyProcessor(processor, source.Bounds);
return source;
}
=> source.ApplyProcessor(new CropProcessor<TPixel>(cropRectangle));
}
}

9
src/ImageSharp/Processing/Transforms/EntropyCrop.cs

@ -23,13 +23,8 @@ namespace ImageSharp
/// <param name="source">The image to crop.</param>
/// <param name="threshold">The threshold for entropic density.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> EntropyCrop<TPixel>(this Image<TPixel> source, float threshold = .5f)
public static IImageProcessingContext<TPixel> EntropyCrop<TPixel>(this IImageProcessingContext<TPixel> source, float threshold = .5f)
where TPixel : struct, IPixel<TPixel>
{
EntropyCropProcessor<TPixel> processor = new EntropyCropProcessor<TPixel>(threshold);
source.ApplyProcessor(processor, source.Bounds);
return source;
}
=> source.ApplyProcessor(new EntropyCropProcessor<TPixel>(threshold));
}
}

9
src/ImageSharp/Processing/Transforms/Flip.cs

@ -24,13 +24,8 @@ namespace ImageSharp
/// <param name="source">The image to rotate, flip, or both.</param>
/// <param name="flipType">The <see cref="FlipType"/> to perform the flip.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> Flip<TPixel>(this Image<TPixel> source, FlipType flipType)
public static IImageProcessingContext<TPixel> Flip<TPixel>(this IImageProcessingContext<TPixel> source, FlipType flipType)
where TPixel : struct, IPixel<TPixel>
{
FlipProcessor<TPixel> processor = new FlipProcessor<TPixel>(flipType);
source.ApplyProcessor(processor, source.Bounds);
return source;
}
=> source.ApplyProcessor(new FlipProcessor<TPixel>(flipType));
}
}

2
src/ImageSharp/Processing/Transforms/Pad.cs

@ -26,7 +26,7 @@ namespace ImageSharp
/// <param name="width">The new width.</param>
/// <param name="height">The new height.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Pad<TPixel>(this Image<TPixel> source, int width, int height)
public static IImageProcessingContext<TPixel> Pad<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height)
where TPixel : struct, IPixel<TPixel>
{
ResizeOptions options = new ResizeOptions

123
src/ImageSharp/Processing/Transforms/Resize.cs

@ -24,23 +24,27 @@ namespace ImageSharp
/// <param name="options">The resize options.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width within the resize options will automatically preserve the aspect ratio of the original image</remarks>
public static Image<TPixel> Resize<TPixel>(this Image<TPixel> source, ResizeOptions options)
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, ResizeOptions options)
where TPixel : struct, IPixel<TPixel>
{
// Ensure size is populated across both dimensions.
if (options.Size.Width == 0 && options.Size.Height > 0)
return source.Apply(img =>
{
options.Size = new Size((int)MathF.Round(source.Width * options.Size.Height / (float)source.Height), options.Size.Height);
}
if (options.Size.Height == 0 && options.Size.Width > 0)
{
options.Size = new Size(options.Size.Width, (int)MathF.Round(source.Height * options.Size.Width / (float)source.Width));
}
Rectangle targetRectangle = ResizeHelper.CalculateTargetLocationAndBounds(source, options);
return Resize(source, options.Size.Width, options.Size.Height, options.Sampler, source.Bounds, targetRectangle, options.Compand);
// Cheat and bound through a run, inside here we should just be mutating, this really needs moving over to a processor
// Ensure size is populated across both dimensions.
if (options.Size.Width == 0 && options.Size.Height > 0)
{
options.Size = new Size((int)MathF.Round(img.Width * options.Size.Height / (float)img.Height), options.Size.Height);
}
if (options.Size.Height == 0 && options.Size.Width > 0)
{
options.Size = new Size(options.Size.Width, (int)MathF.Round(img.Height * options.Size.Width / (float)img.Width));
}
Rectangle targetRectangle = ResizeHelper.CalculateTargetLocationAndBounds(img, options);
img.Mutate(x => Resize(x, options.Size.Width, options.Size.Height, options.Sampler, targetRectangle, options.Compand));
});
}
/// <summary>
@ -51,7 +55,7 @@ namespace ImageSharp
/// <param name="size">The target image size.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static Image<TPixel> Resize<TPixel>(this Image<TPixel> source, Size size)
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, Size size)
where TPixel : struct, IPixel<TPixel>
{
return Resize(source, size.Width, size.Height, new BicubicResampler(), false);
@ -66,7 +70,7 @@ namespace ImageSharp
/// <param name="compand">Whether to compress and expand the image color-space to gamma correct the image during processing.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static Image<TPixel> Resize<TPixel>(this Image<TPixel> source, Size size, bool compand)
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, Size size, bool compand)
where TPixel : struct, IPixel<TPixel>
{
return Resize(source, size.Width, size.Height, new BicubicResampler(), compand);
@ -81,7 +85,7 @@ namespace ImageSharp
/// <param name="height">The target image height.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static Image<TPixel> Resize<TPixel>(this Image<TPixel> source, int width, int height)
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height)
where TPixel : struct, IPixel<TPixel>
{
return Resize(source, width, height, new BicubicResampler(), false);
@ -97,7 +101,7 @@ namespace ImageSharp
/// <param name="compand">Whether to compress and expand the image color-space to gamma correct the image during processing.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static Image<TPixel> Resize<TPixel>(this Image<TPixel> source, int width, int height, bool compand)
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, bool compand)
where TPixel : struct, IPixel<TPixel>
{
return Resize(source, width, height, new BicubicResampler(), compand);
@ -113,7 +117,7 @@ namespace ImageSharp
/// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static Image<TPixel> Resize<TPixel>(this Image<TPixel> source, int width, int height, IResampler sampler)
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, IResampler sampler)
where TPixel : struct, IPixel<TPixel>
{
return Resize(source, width, height, sampler, false);
@ -130,10 +134,10 @@ namespace ImageSharp
/// <param name="compand">Whether to compress and expand the image color-space to gamma correct the image during processing.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static Image<TPixel> Resize<TPixel>(this Image<TPixel> source, int width, int height, IResampler sampler, bool compand)
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, IResampler sampler, bool compand)
where TPixel : struct, IPixel<TPixel>
{
return Resize(source, width, height, sampler, source.Bounds, new Rectangle(0, 0, width, height), compand);
return Resize(source, width, height, sampler, new Rectangle(0, 0, width, height), compand);
}
/// <summary>
@ -154,28 +158,69 @@ namespace ImageSharp
/// <param name="compand">Whether to compress and expand the image color-space to gamma correct the image during processing.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static Image<TPixel> Resize<TPixel>(this Image<TPixel> source, int width, int height, IResampler sampler, Rectangle sourceRectangle, Rectangle targetRectangle, bool compand)
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, IResampler sampler, Rectangle sourceRectangle, Rectangle targetRectangle, bool compand)
where TPixel : struct, IPixel<TPixel>
{
if (width == 0 && height > 0)
return source.Apply(img =>
{
width = (int)MathF.Round(source.Width * height / (float)source.Height);
targetRectangle.Width = width;
}
// TODO : Stop cheating here and move this stuff into the processors itself
if (width == 0 && height > 0)
{
width = (int)MathF.Round(img.Width * height / (float)img.Height);
targetRectangle.Width = width;
}
if (height == 0 && width > 0)
{
height = (int)MathF.Round(img.Height * width / (float)img.Width);
targetRectangle.Height = height;
}
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
img.Mutate(x => x.ApplyProcessor(new ResizeProcessor<TPixel>(sampler, width, height, targetRectangle) { Compand = compand }, sourceRectangle));
});
}
if (height == 0 && width > 0)
/// <summary>
/// Resizes an image to the given width and height with the given sampler and
/// source rectangle.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image to resize.</param>
/// <param name="width">The target image width.</param>
/// <param name="height">The target image height.</param>
/// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
/// <param name="targetRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the target image object to draw to.
/// </param>
/// <param name="compand">Whether to compress and expand the image color-space to gamma correct the image during processing.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
/// <remarks>Passing zero for one of height or width will automatically preserve the aspect ratio of the original image</remarks>
public static IImageProcessingContext<TPixel> Resize<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height, IResampler sampler, Rectangle targetRectangle, bool compand)
where TPixel : struct, IPixel<TPixel>
{
return source.Apply(img =>
{
height = (int)MathF.Round(source.Height * width / (float)source.Width);
targetRectangle.Height = height;
}
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
var processor = new ResizeProcessor<TPixel>(sampler, width, height, targetRectangle) { Compand = compand };
source.ApplyProcessor(processor, sourceRectangle);
return source;
// TODO : stop cheating here and move this stuff into the processors itself
if (width == 0 && height > 0)
{
width = (int)MathF.Round(img.Width * height / (float)img.Height);
targetRectangle.Width = width;
}
if (height == 0 && width > 0)
{
height = (int)MathF.Round(img.Height * width / (float)img.Width);
targetRectangle.Height = height;
}
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
img.Mutate(x => x.ApplyProcessor(new ResizeProcessor<TPixel>(sampler, width, height, targetRectangle) { Compand = compand }));
});
}
}
}
}

17
src/ImageSharp/Processing/Transforms/Rotate.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <param name="source">The image to rotate.</param>
/// <param name="degrees">The angle in degrees to perform the rotation.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> Rotate<TPixel>(this Image<TPixel> source, float degrees)
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees)
where TPixel : struct, IPixel<TPixel>
{
return Rotate(source, degrees, true);
@ -37,11 +37,9 @@ namespace ImageSharp
/// <param name="source">The image to rotate.</param>
/// <param name="rotateType">The <see cref="RotateType"/> to perform the rotation.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> Rotate<TPixel>(this Image<TPixel> source, RotateType rotateType)
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, RotateType rotateType)
where TPixel : struct, IPixel<TPixel>
{
return Rotate(source, (float)rotateType, false);
}
=> Rotate(source, (float)rotateType, false);
/// <summary>
/// Rotates an image by the given angle in degrees.
@ -51,13 +49,8 @@ namespace ImageSharp
/// <param name="degrees">The angle in degrees to perform the rotation.</param>
/// <param name="expand">Whether to expand the image to fit the rotated result.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> Rotate<TPixel>(this Image<TPixel> source, float degrees, bool expand)
public static IImageProcessingContext<TPixel> Rotate<TPixel>(this IImageProcessingContext<TPixel> source, float degrees, bool expand)
where TPixel : struct, IPixel<TPixel>
{
RotateProcessor<TPixel> processor = new RotateProcessor<TPixel> { Angle = degrees, Expand = expand };
source.ApplyProcessor(processor, source.Bounds);
return source;
}
=> source.ApplyProcessor(new RotateProcessor<TPixel> { Angle = degrees, Expand = expand });
}
}

2
src/ImageSharp/Processing/Transforms/RotateFlip.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <param name="rotateType">The <see cref="RotateType"/> to perform the rotation.</param>
/// <param name="flipType">The <see cref="FlipType"/> to perform the flip.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> RotateFlip<TPixel>(this Image<TPixel> source, RotateType rotateType, FlipType flipType)
public static IImageProcessingContext<TPixel> RotateFlip<TPixel>(this IImageProcessingContext<TPixel> source, RotateType rotateType, FlipType flipType)
where TPixel : struct, IPixel<TPixel>
{
return source.Rotate(rotateType).Flip(flipType);

11
src/ImageSharp/Processing/Transforms/Skew.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <param name="degreesX">The angle in degrees to perform the rotation along the x-axis.</param>
/// <param name="degreesY">The angle in degrees to perform the rotation along the y-axis.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> Skew<TPixel>(this Image<TPixel> source, float degreesX, float degreesY)
public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY)
where TPixel : struct, IPixel<TPixel>
{
return Skew(source, degreesX, degreesY, true);
@ -39,13 +39,8 @@ namespace ImageSharp
/// <param name="degreesY">The angle in degrees to perform the rotation along the y-axis.</param>
/// <param name="expand">Whether to expand the image to fit the skewed result.</param>
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static Image<TPixel> Skew<TPixel>(this Image<TPixel> source, float degreesX, float degreesY, bool expand)
public static IImageProcessingContext<TPixel> Skew<TPixel>(this IImageProcessingContext<TPixel> source, float degreesX, float degreesY, bool expand)
where TPixel : struct, IPixel<TPixel>
{
SkewProcessor<TPixel> processor = new SkewProcessor<TPixel> { AngleX = degreesX, AngleY = degreesY, Expand = expand };
source.ApplyProcessor(processor, source.Bounds);
return source;
}
=> source.ApplyProcessor(new SkewProcessor<TPixel> { AngleX = degreesX, AngleY = degreesY, Expand = expand });
}
}

45
src/ImageSharp/Quantizers/Quantize.cs

@ -24,7 +24,7 @@ namespace ImageSharp
/// <param name="mode">The quantization mode to apply to perform the operation.</param>
/// <param name="maxColors">The maximum number of colors to return. Defaults to 256.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Quantize<TPixel>(this Image<TPixel> source, Quantization mode = Quantization.Octree, int maxColors = 256)
public static IImageProcessingContext<TPixel> Quantize<TPixel>(this IImageProcessingContext<TPixel> source, Quantization mode = Quantization.Octree, int maxColors = 256)
where TPixel : struct, IPixel<TPixel>
{
IQuantizer<TPixel> quantizer;
@ -54,31 +54,34 @@ namespace ImageSharp
/// <param name="quantizer">The quantizer to apply to perform the operation.</param>
/// <param name="maxColors">The maximum number of colors to return.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Quantize<TPixel>(this Image<TPixel> source, IQuantizer<TPixel> quantizer, int maxColors)
public static IImageProcessingContext<TPixel> Quantize<TPixel>(this IImageProcessingContext<TPixel> source, IQuantizer<TPixel> quantizer, int maxColors)
where TPixel : struct, IPixel<TPixel>
{
QuantizedImage<TPixel> quantized = quantizer.Quantize(source, maxColors);
int palleteCount = quantized.Palette.Length - 1;
using (PixelAccessor<TPixel> pixels = new PixelAccessor<TPixel>(quantized.Width, quantized.Height))
return source.Apply(img =>
{
Parallel.For(
0,
pixels.Height,
source.Configuration.ParallelOptions,
y =>
{
for (int x = 0; x < pixels.Width; x++)
// TODO : move helper logic into the processor
QuantizedImage<TPixel> quantized = quantizer.Quantize(img, maxColors);
int palleteCount = quantized.Palette.Length - 1;
using (var pixels = new PixelAccessor<TPixel>(quantized.Width, quantized.Height))
{
Parallel.For(
0,
pixels.Height,
img.Configuration.ParallelOptions,
y =>
{
int i = x + (y * pixels.Width);
TPixel color = quantized.Palette[Math.Min(palleteCount, quantized.Pixels[i])];
pixels[x, y] = color;
}
});
for (int x = 0; x < pixels.Width; x++)
{
int i = x + (y * pixels.Width);
TPixel color = quantized.Palette[Math.Min(palleteCount, quantized.Pixels[i])];
pixels[x, y] = color;
}
});
source.SwapPixelsBuffers(pixels);
return source;
}
img.SwapPixelsBuffers(pixels);
}
});
}
}
}

2
src/ImageSharp/Quantizers/Quantizer{TPixel}.cs

@ -70,7 +70,7 @@ namespace ImageSharp.Quantizers
if (this.Dither)
{
// We clone the image as we don't want to alter the original.
using (var clone = new Image<TPixel>(image))
using (ImageBase<TPixel> clone = image.Clone())
{
this.SecondPass(clone, quantizedPixels, width, height);
}

4
src/Shared/AssemblyInfo.Common.cs

@ -37,4 +37,6 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("ImageSharp.Drawing")]
[assembly: InternalsVisibleTo("ImageSharp.Benchmarks")]
[assembly: InternalsVisibleTo("ImageSharp.Tests")]
[assembly: InternalsVisibleTo("ImageSharp.Sandbox46")]
[assembly: InternalsVisibleTo("ImageSharp.Sandbox46")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

4
tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs

@ -47,7 +47,7 @@ namespace ImageSharp.Benchmarks
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
{
image.DrawBeziers(
image.Mutate(x => x.DrawBeziers(
Rgba32.HotPink,
10,
new SixLabors.Primitives.PointF[] {
@ -55,7 +55,7 @@ namespace ImageSharp.Benchmarks
new Vector2(30, 10),
new Vector2(240, 30),
new Vector2(300, 500)
});
}));
using (MemoryStream ms = new MemoryStream())
{

4
tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs

@ -45,14 +45,14 @@ namespace ImageSharp.Benchmarks
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
{
image.DrawLines(
image.Mutate(x => x.DrawLines(
Rgba32.HotPink,
10,
new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
}));
using (MemoryStream ms = new MemoryStream())
{

4
tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs

@ -47,14 +47,14 @@ namespace ImageSharp.Benchmarks
{
using (Image<Rgba32> image = new Image<Rgba32>(800, 800))
{
image.DrawPolygon(
image.Mutate(x => x.DrawPolygon(
Rgba32.HotPink,
10,
new SixLabors.Primitives.PointF[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
}));
using (MemoryStream ms = new MemoryStream())
{

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save