From e1d39de2a6227a00a2406ef92c08a2ef2677c7c5 Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Fri, 5 Oct 2018 00:41:07 -0230 Subject: [PATCH 001/213] Addition of Breadley AdaptiveThreshold --- .../Processing/AdaptiveThresholdExtensions.cs | 47 +++++++ .../AdaptiveThresholdProcessor.cs | 115 ++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs create mode 100644 src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs diff --git a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs new file mode 100644 index 0000000000..9a6d63342f --- /dev/null +++ b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs @@ -0,0 +1,47 @@ +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Extensions to perform AdaptiveThreshold through Mutator + /// + public static class AdaptiveThresholdExtensions + { + /// + /// Applies Bradley Adaptive Threshold to the image. + /// + /// The image this method extends. + /// The pixel format. + /// The . + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source) + where TPixel : struct, IPixel + => source.ApplyProcessor(new AdaptiveThresholdProcessor()); + + /// + /// Applies Bradley Adaptive Threshold to the image. + /// + /// The image this method extends. + /// Upper (white) color for thresholding. + /// Lower (black) color for thresholding + /// /// The pixel format. + /// The . + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower) + where TPixel : struct, IPixel + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower)); + + /// + /// Applies Bradley Adaptive Threshold to the image. + /// + /// The image this method extends. + /// Upper (white) color for thresholding. + /// Lower (black) color for thresholding + /// Rectangle region to apply the processor on. + /// The pixel format. + /// The . + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, Rectangle rectangle) + where TPixel : struct, IPixel + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower), rectangle); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs new file mode 100644 index 0000000000..b14de6679f --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -0,0 +1,115 @@ +using System; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors +{ + /// + /// Performs Bradley Adaptive Threshold filter against an image + /// + /// The pixel format of the image + internal class AdaptiveThresholdProcessor : IImageProcessor + where TPixel : struct, IPixel + { + /// + /// Initializes a new instance of the class. + /// + public AdaptiveThresholdProcessor() + : this(NamedColors.White, NamedColors.Black) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Color for upper threshold + /// Color for lower threshold + public AdaptiveThresholdProcessor(TPixel upper, TPixel lower) + { + this.Upper = upper; + this.Lower = lower; + } + + /// + /// Gets or sets upper color limit for thresholding + /// + public TPixel Upper { get; set; } + + /// + /// Gets or sets lower color limit for threshold + /// + public TPixel Lower { get; set; } + + public unsafe void Apply(Image source, Rectangle sourceRectangle) + { + ushort xStart = (ushort)Math.Max(0, sourceRectangle.X); + ushort yStart = (ushort)Math.Max(0, sourceRectangle.Y); + ushort xEnd = (ushort)Math.Min(xStart + sourceRectangle.Width, source.Width); + ushort yEnd = (ushort)Math.Min(yStart + sourceRectangle.Height, source.Height); + + // Algorithm variables + uint sum, count; + ushort s = (ushort)Math.Truncate((xEnd / 16f) - 1); + uint[,] intImage = new uint[yEnd, xEnd]; + + // Trying to figure out how to do this + // Using (Buffer2D intImg = source.GetConfiguration().MemoryAllocator.Allocate2D) + Rgb24 rgb = default; + + for (ushort i = yStart; i < yEnd; i++) + { + Span span = source.GetPixelRowSpan(i); + + sum = 0; + + for (ushort j = xStart; j < xEnd; j++) + { + span[j].ToRgb24(ref rgb); + + sum += (uint)(rgb.R + rgb.G + rgb.B); + + if (i != 0) + { + intImage[i, j] = intImage[i - 1, j] + sum; + } + else + { + intImage[i, j] = sum; + } + } + } + + // How can I parallelize this? + ushort x1, x2, y1, y2; + + for (ushort i = yStart; i < yEnd; i++) + { + Span span = source.GetPixelRowSpan(i); + + for (ushort j = xStart; j < xEnd; j++) + { + x1 = (ushort)Math.Max(i - s + 1, 0); + x2 = (ushort)Math.Min(i + s + 1, yEnd - 1); + y1 = (ushort)Math.Max(j - s + 1, 0); + y2 = (ushort)Math.Min(j + s + 1, xEnd - 1); + + count = (ushort)((x2 - x1) * (y2 - y1)); + + sum = intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]; + + span[j].ToRgb24(ref rgb); + + if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) + { + span[j] = this.Lower; + } + else + { + span[j] = this.Upper; + } + } + } + } + } +} \ No newline at end of file From 152b8e680d584bec691e56c68f3100137c8a0e3c Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Fri, 5 Oct 2018 12:35:15 -0230 Subject: [PATCH 002/213] # Added Rect.Intersect # Inherited from ImageProcessor # Minor changes to variables # Minor Tweaks --- .../AdaptiveThresholdProcessor.cs | 107 ++++++++++-------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index b14de6679f..46e2e67c0d 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -1,6 +1,8 @@ using System; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors @@ -9,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Performs Bradley Adaptive Threshold filter against an image /// /// The pixel format of the image - internal class AdaptiveThresholdProcessor : IImageProcessor + internal class AdaptiveThresholdProcessor : ImageProcessor where TPixel : struct, IPixel { /// @@ -41,72 +43,81 @@ namespace SixLabors.ImageSharp.Processing.Processors /// public TPixel Lower { get; set; } - public unsafe void Apply(Image source, Rectangle sourceRectangle) + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - ushort xStart = (ushort)Math.Max(0, sourceRectangle.X); - ushort yStart = (ushort)Math.Max(0, sourceRectangle.Y); - ushort xEnd = (ushort)Math.Min(xStart + sourceRectangle.Width, source.Width); - ushort yEnd = (ushort)Math.Min(yStart + sourceRectangle.Height, source.Height); + var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + ushort startY = (ushort)interest.Y; + ushort endY = (ushort)interest.Bottom; + ushort startX = (ushort)interest.X; + ushort endX = (ushort)interest.Right; - // Algorithm variables - uint sum, count; - ushort s = (ushort)Math.Truncate((xEnd / 16f) - 1); - uint[,] intImage = new uint[yEnd, xEnd]; + ushort width = (ushort)(endX - startX); + ushort height = (ushort)(endY - startY); - // Trying to figure out how to do this - // Using (Buffer2D intImg = source.GetConfiguration().MemoryAllocator.Allocate2D) - Rgb24 rgb = default; + // Algorithm variables // + ulong sum; + uint count; - for (ushort i = yStart; i < yEnd; i++) - { - Span span = source.GetPixelRowSpan(i); + // Tweaked to support upto 4k wide pixels + ushort s = (ushort)Math.Truncate((width / 16f) - 1); - sum = 0; + // Trying to figure out how to do this + using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height, AllocationOptions.Clean)) + { + Rgb24 rgb = default; - for (ushort j = xStart; j < xEnd; j++) + for (ushort i = startY; i < endY; i++) { - span[j].ToRgb24(ref rgb); + Span span = source.GetPixelRowSpan(i); - sum += (uint)(rgb.R + rgb.G + rgb.B); + sum = 0; - if (i != 0) + for (ushort j = startX; j < endX; j++) { - intImage[i, j] = intImage[i - 1, j] + sum; - } - else - { - intImage[i, j] = sum; + span[j].ToRgb24(ref rgb); + + sum += (uint)(rgb.R + rgb.G + rgb.B); + + if (i != 0) + { + intImage[i, j] = intImage[i - 1, j] + sum; + } + else + { + intImage[i, j] = sum; + } } } - } - // How can I parallelize this? - ushort x1, x2, y1, y2; + // How can I parallelize this? + ushort x1, x2, y1, y2; - for (ushort i = yStart; i < yEnd; i++) - { - Span span = source.GetPixelRowSpan(i); - - for (ushort j = xStart; j < xEnd; j++) + for (ushort i = startY; i < endY; i++) { - x1 = (ushort)Math.Max(i - s + 1, 0); - x2 = (ushort)Math.Min(i + s + 1, yEnd - 1); - y1 = (ushort)Math.Max(j - s + 1, 0); - y2 = (ushort)Math.Min(j + s + 1, xEnd - 1); + Span span = source.GetPixelRowSpan(i); - count = (ushort)((x2 - x1) * (y2 - y1)); + for (ushort j = startX; j < endX; j++) + { + x1 = (ushort)Math.Max(i - s + 1, 0); + x2 = (ushort)Math.Min(i + s + 1, endY - 1); + y1 = (ushort)Math.Max(j - s + 1, 0); + y2 = (ushort)Math.Min(j + s + 1, endX - 1); - sum = intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]; + count = (uint)((x2 - x1) * (y2 - y1)); - span[j].ToRgb24(ref rgb); + sum = intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]; - if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) - { - span[j] = this.Lower; - } - else - { - span[j] = this.Upper; + span[j].ToRgb24(ref rgb); + + if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) + { + span[j] = this.Lower; + } + else + { + span[j] = this.Upper; + } } } } From 95a7b0db1a127c728ff33d80c708392184d5c420 Mon Sep 17 00:00:00 2001 From: SimantoR Date: Sat, 13 Oct 2018 04:01:48 -0230 Subject: [PATCH 003/213] Added parallelism to loops --- .../AdaptiveThresholdProcessor.cs | 127 +++++++++++------- tests/Images/External | 2 +- 2 files changed, 76 insertions(+), 53 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 46e2e67c0d..898e1f8fd7 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -1,6 +1,11 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -46,80 +51,98 @@ namespace SixLabors.ImageSharp.Processing.Processors /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); - ushort startY = (ushort)interest.Y; - ushort endY = (ushort)interest.Bottom; - ushort startX = (ushort)interest.X; - ushort endX = (ushort)interest.Right; + var intersect = Rectangle.Intersect(sourceRectangle, source.Bounds()); + ushort startY = (ushort)intersect.Y; + ushort endY = (ushort)intersect.Bottom; + ushort startX = (ushort)intersect.X; + ushort endX = (ushort)intersect.Right; ushort width = (ushort)(endX - startX); ushort height = (ushort)(endY - startY); - // Algorithm variables // - ulong sum; - uint count; - - // Tweaked to support upto 4k wide pixels - ushort s = (ushort)Math.Truncate((width / 16f) - 1); + // Tweaked to support upto 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1' + byte s = (byte)Math.Truncate((width / 16f) - 1); - // Trying to figure out how to do this + // Using pooled 2d buffer for integer image table using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height, AllocationOptions.Clean)) { - Rgb24 rgb = default; - - for (ushort i = startY; i < endY; i++) - { - Span span = source.GetPixelRowSpan(i); - - sum = 0; + var workingnRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); - for (ushort j = startX; j < endX; j++) + ParallelHelper.IterateRows( + workingnRectangle, + configuration, + rows => { - span[j].ToRgb24(ref rgb); + ulong sum; - sum += (uint)(rgb.R + rgb.G + rgb.B); + Rgb24 rgb = default; - if (i != 0) + for (int i = rows.Min; i < rows.Max; i++) { - intImage[i, j] = intImage[i - 1, j] + sum; - } - else - { - intImage[i, j] = sum; + var row = source.GetPixelRowSpan(i); + + sum = 0; + + for (int j = startX; j < endX; j++) + { + row[j].ToRgb24(ref rgb); + sum += (ulong)(rgb.B + rgb.G + rgb.B); + + if (i != 0) + { + intImage[i, j] = intImage[i - 1, j] + sum; + } + else + { + intImage[i, j] = sum; + } + } } } - } + ); - // How can I parallelize this? - ushort x1, x2, y1, y2; + ParallelHelper.IterateRows( + workingnRectangle, + configuration, + rows => + { + ushort x1, x2, y1, y2; - for (ushort i = startY; i < endY; i++) - { - Span span = source.GetPixelRowSpan(i); + uint count; - for (ushort j = startX; j < endX; j++) - { - x1 = (ushort)Math.Max(i - s + 1, 0); - x2 = (ushort)Math.Min(i + s + 1, endY - 1); - y1 = (ushort)Math.Max(j - s + 1, 0); - y2 = (ushort)Math.Min(j + s + 1, endX - 1); + long sum; - count = (uint)((x2 - x1) * (y2 - y1)); + for (int i = rows.Min; i < rows.Max; i++) + { + var row = source.GetPixelRowSpan(i); - sum = intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]; + Rgb24 rgb = default; - span[j].ToRgb24(ref rgb); + for (int j = startX; j < endX; j++) + { + x1 = (ushort)Math.Max(i - s + 1, 0); + x2 = (ushort)Math.Min(i + s + 1, endY - 1); + y1 = (ushort)Math.Max(j - s + 1, 0); + y2 = (ushort)Math.Min(j + s + 1, endX - 1); - if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) - { - span[j] = this.Lower; - } - else - { - span[j] = this.Upper; + count = (uint)((x2 - x1) * (y2 - y1)); + + sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); + + row[j].ToRgb24(ref rgb); + + if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) + { + row[j] = this.Lower; + } + else + { + row[j] = this.Upper; + } + } } } - } + ); } } } diff --git a/tests/Images/External b/tests/Images/External index ee90e5f322..5f3cbd839f 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit ee90e5f32218027744b5d40058b587cc1047b76f +Subproject commit 5f3cbd839fbbffae615d294d1dabafdcabc64cf9 From 2b6d93aabe3b958b6376c6ef598b056ec5d5e443 Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Wed, 24 Oct 2018 13:38:07 -0230 Subject: [PATCH 004/213] Temporary fix to accomodate #744 --- .../AdaptiveThresholdProcessor.cs | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 898e1f8fd7..baecdf7f0d 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Threading.Tasks; +using System.Buffers; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; @@ -34,8 +34,8 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Color for lower threshold public AdaptiveThresholdProcessor(TPixel upper, TPixel lower) { - this.Upper = upper; - this.Lower = lower; + this.Upper.PackFromRgba32(upper.ToRgba32()); + this.Lower.PackFromRgba32(lower.ToRgba32()); } /// @@ -75,26 +75,29 @@ namespace SixLabors.ImageSharp.Processing.Processors { ulong sum; - Rgb24 rgb = default; - for (int i = rows.Min; i < rows.Max; i++) { - var row = source.GetPixelRowSpan(i); - - sum = 0; - - for (int j = startX; j < endX; j++) + using (IMemoryOwner tmpPixels = configuration.MemoryAllocator.Allocate(width, AllocationOptions.None)) { - row[j].ToRgb24(ref rgb); - sum += (ulong)(rgb.B + rgb.G + rgb.B); + Span span = tmpPixels.GetSpan(); + PixelOperations.Instance.ToRgb24(source.GetPixelRowSpan(i), span, width); - if (i != 0) - { - intImage[i, j] = intImage[i - 1, j] + sum; - } - else + sum = 0; + + for (int j = startX; j < endX; j++) { - intImage[i, j] = sum; + ref Rgb24 rgb = ref span[(width * j) + i]; + + sum += (ulong)(rgb.B + rgb.G + rgb.B); + + if (i != 0) + { + intImage[i, j] = intImage[i - 1, j] + sum; + } + else + { + intImage[i, j] = sum; + } } } } @@ -114,30 +117,34 @@ namespace SixLabors.ImageSharp.Processing.Processors for (int i = rows.Min; i < rows.Max; i++) { - var row = source.GetPixelRowSpan(i); - - Rgb24 rgb = default; - - for (int j = startX; j < endX; j++) + using (IMemoryOwner tmpPixes = configuration.MemoryAllocator.Allocate(width)) { - x1 = (ushort)Math.Max(i - s + 1, 0); - x2 = (ushort)Math.Min(i + s + 1, endY - 1); - y1 = (ushort)Math.Max(j - s + 1, 0); - y2 = (ushort)Math.Min(j + s + 1, endX - 1); - - count = (uint)((x2 - x1) * (y2 - y1)); - - sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); + Span span = tmpPixes.GetSpan(); + PixelOperations.Instance.ToRgb24(source.GetPixelRowSpan(i), span, width); - row[j].ToRgb24(ref rgb); - - if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) - { - row[j] = this.Lower; - } - else + for (int j = startX; j < endX; j++) { - row[j] = this.Upper; + ref Rgb24 rgb = ref span[(width * j) + 1]; + + x1 = (ushort)Math.Max(i - s + 1, 0); + x2 = (ushort)Math.Min(i + s + 1, endY - 1); + y1 = (ushort)Math.Max(j - s + 1, 0); + y2 = (ushort)Math.Min(j + s + 1, endX - 1); + + count = (uint)((x2 - x1) * (y2 - y1)); + + sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]) + + if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) + { + //row[j] = this.Lower; + rgb = this.Lower.ToRgba32().Rgb; + } + else + { + //row[j] = this.Upper; + rgb = this.Upper.ToRgba32().Rgb; + } } } } From bb5cc29ba2d8d993e10de6c528c90504eb03e228 Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Wed, 24 Oct 2018 13:42:10 -0230 Subject: [PATCH 005/213] Few general changes without effecting the algorithm implementation --- .../AdaptiveThresholdProcessor.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index baecdf7f0d..50dfdfd9e8 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -57,11 +57,13 @@ namespace SixLabors.ImageSharp.Processing.Processors ushort startX = (ushort)intersect.X; ushort endX = (ushort)intersect.Right; - ushort width = (ushort)(endX - startX); - ushort height = (ushort)(endY - startY); + ushort width = (ushort)intersect.Width; + ushort height = (ushort)intersect.Height; // Tweaked to support upto 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1' - byte s = (byte)Math.Truncate((width / 16f) - 1); + byte clusterSize = (byte)((width / 16) - 1); + + float threshold = 0.85f; // Using pooled 2d buffer for integer image table using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height, AllocationOptions.Clean)) @@ -126,23 +128,21 @@ namespace SixLabors.ImageSharp.Processing.Processors { ref Rgb24 rgb = ref span[(width * j) + 1]; - x1 = (ushort)Math.Max(i - s + 1, 0); - x2 = (ushort)Math.Min(i + s + 1, endY - 1); - y1 = (ushort)Math.Max(j - s + 1, 0); - y2 = (ushort)Math.Min(j + s + 1, endX - 1); + x1 = (ushort)Math.Max(i - clusterSize + 1, 0); + x2 = (ushort)Math.Min(i + clusterSize + 1, endY - 1); + y1 = (ushort)Math.Max(j - clusterSize + 1, 0); + y2 = (ushort)Math.Min(j + clusterSize + 1, endX - 1); count = (uint)((x2 - x1) * (y2 - y1)); sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]) - if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15)) + if ((rgb.R + rgb.G + rgb.B) * count < sum * threshold) { - //row[j] = this.Lower; rgb = this.Lower.ToRgba32().Rgb; } else { - //row[j] = this.Upper; rgb = this.Upper.ToRgba32().Rgb; } } From d8f3b397bb063b3695fe7dbe3e65643ed52d289d Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Wed, 24 Oct 2018 13:57:29 -0230 Subject: [PATCH 006/213] Fixed few breaking changes --- .../AdaptiveThresholdProcessor.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 50dfdfd9e8..d13b84b8a4 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -19,6 +19,8 @@ namespace SixLabors.ImageSharp.Processing.Processors internal class AdaptiveThresholdProcessor : ImageProcessor where TPixel : struct, IPixel { + private readonly PixelOperations pixelOpInstance; + /// /// Initializes a new instance of the class. /// @@ -34,19 +36,20 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Color for lower threshold public AdaptiveThresholdProcessor(TPixel upper, TPixel lower) { - this.Upper.PackFromRgba32(upper.ToRgba32()); - this.Lower.PackFromRgba32(lower.ToRgba32()); + this.pixelOpInstance = PixelOperations.Instance; + this.Upper.FromRgba32(upper.ToRgba32()); + this.Lower.FromRgba32(lower.ToRgba32()); } /// /// Gets or sets upper color limit for thresholding /// - public TPixel Upper { get; set; } + public Rgb24 Upper { get; set; } /// /// Gets or sets lower color limit for threshold /// - public TPixel Lower { get; set; } + public Rgb24 Lower { get; set; } /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) @@ -82,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors using (IMemoryOwner tmpPixels = configuration.MemoryAllocator.Allocate(width, AllocationOptions.None)) { Span span = tmpPixels.GetSpan(); - PixelOperations.Instance.ToRgb24(source.GetPixelRowSpan(i), span, width); + this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), span); sum = 0; @@ -122,7 +125,7 @@ namespace SixLabors.ImageSharp.Processing.Processors using (IMemoryOwner tmpPixes = configuration.MemoryAllocator.Allocate(width)) { Span span = tmpPixes.GetSpan(); - PixelOperations.Instance.ToRgb24(source.GetPixelRowSpan(i), span, width); + this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), span); for (int j = startX; j < endX; j++) { @@ -139,11 +142,11 @@ namespace SixLabors.ImageSharp.Processing.Processors if ((rgb.R + rgb.G + rgb.B) * count < sum * threshold) { - rgb = this.Lower.ToRgba32().Rgb; + rgb = this.Lower; } else { - rgb = this.Upper.ToRgba32().Rgb; + rgb = this.Upper; } } } From 8978bc34749b5a335b5aab51658de6a5966c05e7 Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Wed, 24 Oct 2018 14:14:20 -0230 Subject: [PATCH 007/213] Missed an end of line by accident :p --- .../AdaptiveThresholdProcessor.cs | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index d13b84b8a4..b6748ce002 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -77,81 +77,81 @@ namespace SixLabors.ImageSharp.Processing.Processors workingnRectangle, configuration, rows => - { - ulong sum; - - for (int i = rows.Min; i < rows.Max; i++) { - using (IMemoryOwner tmpPixels = configuration.MemoryAllocator.Allocate(width, AllocationOptions.None)) - { - Span span = tmpPixels.GetSpan(); - this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), span); + ulong sum; - sum = 0; - - for (int j = startX; j < endX; j++) + for (int i = rows.Min; i < rows.Max; i++) + { + using (IMemoryOwner tmpPixels = configuration.MemoryAllocator.Allocate(width, AllocationOptions.None)) { - ref Rgb24 rgb = ref span[(width * j) + i]; + Span span = tmpPixels.GetSpan(); + this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), span); - sum += (ulong)(rgb.B + rgb.G + rgb.B); + sum = 0; - if (i != 0) + for (int j = startX; j < endX; j++) { - intImage[i, j] = intImage[i - 1, j] + sum; - } - else - { - intImage[i, j] = sum; + ref Rgb24 rgb = ref span[(width * j) + i]; + + sum += (ulong)(rgb.B + rgb.G + rgb.B); + + if (i != 0) + { + intImage[i, j] = intImage[i - 1, j] + sum; + } + else + { + intImage[i, j] = sum; + } } } } } - } ); ParallelHelper.IterateRows( workingnRectangle, configuration, rows => - { - ushort x1, x2, y1, y2; + { + ushort x1, x2, y1, y2; - uint count; + uint count; - long sum; + long sum; - for (int i = rows.Min; i < rows.Max; i++) - { - using (IMemoryOwner tmpPixes = configuration.MemoryAllocator.Allocate(width)) + for (int i = rows.Min; i < rows.Max; i++) { - Span span = tmpPixes.GetSpan(); - this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), span); - - for (int j = startX; j < endX; j++) + using (IMemoryOwner tmpPixes = configuration.MemoryAllocator.Allocate(width)) { - ref Rgb24 rgb = ref span[(width * j) + 1]; + Span span = tmpPixes.GetSpan(); + this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), span); - x1 = (ushort)Math.Max(i - clusterSize + 1, 0); - x2 = (ushort)Math.Min(i + clusterSize + 1, endY - 1); - y1 = (ushort)Math.Max(j - clusterSize + 1, 0); - y2 = (ushort)Math.Min(j + clusterSize + 1, endX - 1); + for (int j = startX; j < endX; j++) + { + ref Rgb24 rgb = ref span[(width * j) + 1]; - count = (uint)((x2 - x1) * (y2 - y1)); + x1 = (ushort)Math.Max(i - clusterSize + 1, 0); + x2 = (ushort)Math.Min(i + clusterSize + 1, endY - 1); + y1 = (ushort)Math.Max(j - clusterSize + 1, 0); + y2 = (ushort)Math.Min(j + clusterSize + 1, endX - 1); - sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]) + count = (uint)((x2 - x1) * (y2 - y1)); - if ((rgb.R + rgb.G + rgb.B) * count < sum * threshold) - { - rgb = this.Lower; - } - else - { - rgb = this.Upper; + sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); + + if ((rgb.R + rgb.G + rgb.B) * count < sum * threshold) + { + rgb = this.Lower; + } + else + { + rgb = this.Upper; + } } } } } - } ); } } From 6805f6d277eb2be7cd40acaab77185ce1ef78de5 Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Thu, 25 Oct 2018 12:13:48 -0230 Subject: [PATCH 008/213] Used TempBuffer and fixed few logical errors --- .../AdaptiveThresholdProcessor.cs | 130 +++++++++--------- 1 file changed, 62 insertions(+), 68 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index b6748ce002..0602777e35 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -37,19 +37,20 @@ namespace SixLabors.ImageSharp.Processing.Processors public AdaptiveThresholdProcessor(TPixel upper, TPixel lower) { this.pixelOpInstance = PixelOperations.Instance; - this.Upper.FromRgba32(upper.ToRgba32()); - this.Lower.FromRgba32(lower.ToRgba32()); + + this.Upper = upper; + this.Lower = lower; } /// /// Gets or sets upper color limit for thresholding /// - public Rgb24 Upper { get; set; } + public TPixel Upper { get; set; } /// /// Gets or sets lower color limit for threshold /// - public Rgb24 Lower { get; set; } + public TPixel Lower { get; set; } /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) @@ -69,90 +70,83 @@ namespace SixLabors.ImageSharp.Processing.Processors float threshold = 0.85f; // Using pooled 2d buffer for integer image table - using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height, AllocationOptions.Clean)) + using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height)) { - var workingnRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); + var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); - ParallelHelper.IterateRows( - workingnRectangle, + ParallelHelper.IterateRowsWithTempBuffer( + workingRectangle, configuration, - rows => + (rows, memory) => + { + ulong sum = 0; + + Span tmpSpan = memory.Span; + + for (int i = rows.Min; i < rows.Max; i++) { - ulong sum; + this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), tmpSpan); + + sum = 0; - for (int i = rows.Min; i < rows.Max; i++) + for (int j = startX; j < endX; j++) { - using (IMemoryOwner tmpPixels = configuration.MemoryAllocator.Allocate(width, AllocationOptions.None)) + ref Rgb24 rgb = ref tmpSpan[j]; + + sum += (ulong)(rgb.R + rgb.G + rgb.B); + + if (i != 0) + { + intImage[i, j] = intImage[i - 1, j] + sum; + } + else { - Span span = tmpPixels.GetSpan(); - this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), span); - - sum = 0; - - for (int j = startX; j < endX; j++) - { - ref Rgb24 rgb = ref span[(width * j) + i]; - - sum += (ulong)(rgb.B + rgb.G + rgb.B); - - if (i != 0) - { - intImage[i, j] = intImage[i - 1, j] + sum; - } - else - { - intImage[i, j] = sum; - } - } + intImage[i, j] = sum; } } } - ); + }); - ParallelHelper.IterateRows( - workingnRectangle, + ParallelHelper.IterateRowsWithTempBuffer( + workingRectangle, configuration, - rows => - { - ushort x1, x2, y1, y2; + (rows, memory) => + { + ushort x1, x2, y1, y2; + uint count = 0; + long sum = 0; - uint count; + Span tmpSpan = memory.Span; - long sum; + for (int i = rows.Min; i < rows.Max; i++) + { + Span originalSpan = source.GetPixelRowSpan(i); + this.pixelOpInstance.ToRgb24(originalSpan, tmpSpan); - for (int i = rows.Min; i < rows.Max; i++) + for (int j = startX; j < endX; j++) { - using (IMemoryOwner tmpPixes = configuration.MemoryAllocator.Allocate(width)) + ref Rgb24 rgb = ref tmpSpan[j]; + + x1 = (ushort)Math.Max(i - clusterSize + 1, 0); + x2 = (ushort)Math.Min(i + clusterSize + 1, endY - 1); + y1 = (ushort)Math.Max(j - clusterSize + 1, 0); + y2 = (ushort)Math.Min(j + clusterSize + 1, endX - 1); + + count = (uint)((x2 - x1) * (y2 - y1)); + + sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); + + if ((rgb.R + rgb.G + rgb.B) * count < sum * threshold) + { + originalSpan[j] = this.Lower; + } + else { - Span span = tmpPixes.GetSpan(); - this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), span); - - for (int j = startX; j < endX; j++) - { - ref Rgb24 rgb = ref span[(width * j) + 1]; - - x1 = (ushort)Math.Max(i - clusterSize + 1, 0); - x2 = (ushort)Math.Min(i + clusterSize + 1, endY - 1); - y1 = (ushort)Math.Max(j - clusterSize + 1, 0); - y2 = (ushort)Math.Min(j + clusterSize + 1, endX - 1); - - count = (uint)((x2 - x1) * (y2 - y1)); - - sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); - - if ((rgb.R + rgb.G + rgb.B) * count < sum * threshold) - { - rgb = this.Lower; - } - else - { - rgb = this.Upper; - } - } + originalSpan[j] = this.Upper; } } } - ); + }); } } } From b0541025b2804755edc7253aba3cdadf252d6fde Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Thu, 25 Oct 2018 12:50:40 -0230 Subject: [PATCH 009/213] Added contructor to control threshold limit --- .../Processing/AdaptiveThresholdExtensions.cs | 42 ++++++++++++++++++- .../AdaptiveThresholdProcessor.cs | 31 +++++++++++--- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs index 9a6d63342f..6c8795aa5d 100644 --- a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs +++ b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs @@ -1,5 +1,5 @@ using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors; +using SixLabors.ImageSharp.Processing.Processors.Binarization; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing @@ -19,18 +19,42 @@ namespace SixLabors.ImageSharp.Processing where TPixel : struct, IPixel => source.ApplyProcessor(new AdaptiveThresholdProcessor()); + /// + /// Applies Bradley Adaptive Threshold to the image. + /// + /// The image this method extends. + /// Threshold limit (0.0-1.0) to consider for binarization. + /// The pixel format. + /// The . + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, float threshold) + where TPixel : struct, IPixel + => source.ApplyProcessor(new AdaptiveThresholdProcessor(threshold)); + /// /// Applies Bradley Adaptive Threshold to the image. /// /// The image this method extends. /// Upper (white) color for thresholding. /// Lower (black) color for thresholding - /// /// The pixel format. + /// The pixel format. /// The . public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower) where TPixel : struct, IPixel => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower)); + /// + /// Applies Bradley Adaptive Threshold to the image. + /// + /// The image this method extends. + /// Upper (white) color for thresholding. + /// Lower (black) color for thresholding + /// Threshold limit (0.0-1.0) to consider for binarization. + /// The pixel format. + /// The . + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, float threshold) + where TPixel : struct, IPixel + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, threshold)); + /// /// Applies Bradley Adaptive Threshold to the image. /// @@ -43,5 +67,19 @@ namespace SixLabors.ImageSharp.Processing public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, Rectangle rectangle) where TPixel : struct, IPixel => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower), rectangle); + + /// + /// Applies Bradley Adaptive Threshold to the image. + /// + /// The image this method extends. + /// Upper (white) color for thresholding. + /// Lower (black) color for thresholding + /// Threshold limit (0.0-1.0) to consider for binarization. + /// Rectangle region to apply the processor on. + /// The pixel format. + /// The . + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, float threshold, Rectangle rectangle) + where TPixel : struct, IPixel + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, threshold), rectangle); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 0602777e35..2bed73be00 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; -namespace SixLabors.ImageSharp.Processing.Processors +namespace SixLabors.ImageSharp.Processing.Processors.Binarization { /// /// Performs Bradley Adaptive Threshold filter against an image @@ -25,7 +25,21 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Initializes a new instance of the class. /// public AdaptiveThresholdProcessor() - : this(NamedColors.White, NamedColors.Black) + : this(NamedColors.White, NamedColors.Black, 0.85f) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Threshold limit + public AdaptiveThresholdProcessor(float threshold) + : this(NamedColors.White, NamedColors.Black, threshold) + { + } + + public AdaptiveThresholdProcessor(TPixel upper, TPixel lower) + : this(upper, lower, 0.85f) { } @@ -34,12 +48,14 @@ namespace SixLabors.ImageSharp.Processing.Processors /// /// Color for upper threshold /// Color for lower threshold - public AdaptiveThresholdProcessor(TPixel upper, TPixel lower) + /// Threshold limit + public AdaptiveThresholdProcessor(TPixel upper, TPixel lower, float threshold) { this.pixelOpInstance = PixelOperations.Instance; this.Upper = upper; this.Lower = lower; + this.Threshold = threshold; } /// @@ -52,6 +68,11 @@ namespace SixLabors.ImageSharp.Processing.Processors /// public TPixel Lower { get; set; } + /// + /// Gets or sets the value for threshold limit + /// + public float Threshold { get; set; } + /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { @@ -67,8 +88,6 @@ namespace SixLabors.ImageSharp.Processing.Processors // Tweaked to support upto 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1' byte clusterSize = (byte)((width / 16) - 1); - float threshold = 0.85f; - // Using pooled 2d buffer for integer image table using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height)) { @@ -136,7 +155,7 @@ namespace SixLabors.ImageSharp.Processing.Processors sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); - if ((rgb.R + rgb.G + rgb.B) * count < sum * threshold) + if ((rgb.R + rgb.G + rgb.B) * count < sum * this.Threshold) { originalSpan[j] = this.Lower; } From 319fc9559ca9a7773aea2659322626f69029236b Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Fri, 26 Oct 2018 19:22:03 -0230 Subject: [PATCH 010/213] Fixed several bugs produced during parallelism implementations --- .../AdaptiveThresholdProcessor.cs | 74 +++++++++---------- 1 file changed, 33 insertions(+), 41 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 2bed73be00..21c7f4f57c 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization this.Upper = upper; this.Lower = lower; - this.Threshold = threshold; + this.ThresholdLimit = threshold; } /// @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// /// Gets or sets the value for threshold limit /// - public float Threshold { get; set; } + public float ThresholdLimit { get; set; } /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) @@ -90,81 +90,73 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Using pooled 2d buffer for integer image table using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height)) + using (IMemoryOwner tmpBuffer = configuration.MemoryAllocator.Allocate(width * height)) { - var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); + Rectangle workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); - ParallelHelper.IterateRowsWithTempBuffer( + this.pixelOpInstance.ToRgb24(source.GetPixelSpan(), tmpBuffer.GetSpan()); + + ParallelHelper.IterateRows( workingRectangle, configuration, - (rows, memory) => + rows => { - ulong sum = 0; - - Span tmpSpan = memory.Span; - - for (int i = rows.Min; i < rows.Max; i++) + Span rgbSpan = tmpBuffer.GetSpan(); + uint sum; + for (int x = startX; x < endX; x++) { - this.pixelOpInstance.ToRgb24(source.GetPixelRowSpan(i), tmpSpan); - sum = 0; - - for (int j = startX; j < endX; j++) + for (int y = rows.Min; y < rows.Max; y++) { - ref Rgb24 rgb = ref tmpSpan[j]; - - sum += (ulong)(rgb.R + rgb.G + rgb.B); + ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; + sum += (uint)(rgb.R + rgb.G + rgb.B); - if (i != 0) + if (x > 0) { - intImage[i, j] = intImage[i - 1, j] + sum; + intImage[x - startX, y - startY] = intImage[x - 1 - startX, y - startY] + sum; } else { - intImage[i, j] = sum; + intImage[x - startX, y - startY] = sum; } } } }); - ParallelHelper.IterateRowsWithTempBuffer( + ParallelHelper.IterateRows( workingRectangle, configuration, - (rows, memory) => + rows => { ushort x1, x2, y1, y2; - uint count = 0; + Span rgbSpan = tmpBuffer.GetSpan(); long sum = 0; + uint count = 0; - Span tmpSpan = memory.Span; - - for (int i = rows.Min; i < rows.Max; i++) + for (int x = startX; x < endX; x++) { - Span originalSpan = source.GetPixelRowSpan(i); - this.pixelOpInstance.ToRgb24(originalSpan, tmpSpan); - - for (int j = startX; j < endX; j++) + for (int y = rows.Min; y < rows.Max; y++) { - ref Rgb24 rgb = ref tmpSpan[j]; - - x1 = (ushort)Math.Max(i - clusterSize + 1, 0); - x2 = (ushort)Math.Min(i + clusterSize + 1, endY - 1); - y1 = (ushort)Math.Max(j - clusterSize + 1, 0); - y2 = (ushort)Math.Min(j + clusterSize + 1, endX - 1); + ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; + x1 = (ushort)Math.Max(x - clusterSize + 1 - startX, 0); + x2 = (ushort)Math.Min(x + clusterSize + 1 - startX, endX - startX - 1); + y1 = (ushort)Math.Max(y - clusterSize + 1 - startY, 0); + y2 = (ushort)Math.Min(y + clusterSize + 1 - startY, endY - startY - 1); count = (uint)((x2 - x1) * (y2 - y1)); - sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); + sum = (long)(intImage[x2, y2] - intImage[x2, y1] - intImage[x1, y2] + intImage[x1, y1]); - if ((rgb.R + rgb.G + rgb.B) * count < sum * this.Threshold) + if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.ThresholdLimit) { - originalSpan[j] = this.Lower; + source[x, y] = this.Lower; } else { - originalSpan[j] = this.Upper; + source[x, y] = this.Upper; } } - } + } }); } } From a239e60885030c15d3fffa505415657c159f5b4d Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Tue, 30 Oct 2018 13:52:02 -0230 Subject: [PATCH 011/213] Algorithm behaves abnormally when applied with ParallelHelpers --- .../AdaptiveThresholdProcessor.cs | 118 +++++++++--------- 1 file changed, 57 insertions(+), 61 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 21c7f4f57c..030768e69b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -76,7 +76,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - var intersect = Rectangle.Intersect(sourceRectangle, source.Bounds()); + Rectangle intersect = Rectangle.Intersect(sourceRectangle, source.Bounds()); + + // Used ushort because the values should never exceed max ushort value ushort startY = (ushort)intersect.Y; ushort endY = (ushort)intersect.Bottom; ushort startX = (ushort)intersect.X; @@ -85,79 +87,73 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization ushort width = (ushort)intersect.Width; ushort height = (ushort)intersect.Height; - // Tweaked to support upto 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1' - byte clusterSize = (byte)((width / 16) - 1); + // ClusterSize defines the size of cluster to used to check for average. Tweaked to support upto 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1' + byte clusterSize = (byte)Math.Truncate((width / 16f) - 1); - // Using pooled 2d buffer for integer image table + // Using pooled 2d buffer for integer image table and temp memory to hold Rgb24 converted pixel data using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height)) - using (IMemoryOwner tmpBuffer = configuration.MemoryAllocator.Allocate(width * height)) + using (IMemoryOwner bulkRgbBuf = configuration.MemoryAllocator.Allocate(width * height)) { + // Defines the rectangle section of the image to work on Rectangle workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); - this.pixelOpInstance.ToRgb24(source.GetPixelSpan(), tmpBuffer.GetSpan()); + // TPixel span of the original image + Span pixelSpan = source.GetPixelSpan(); + + // RGB24 span of the converted pixel buffer + Span rgbSpan = bulkRgbBuf.GetSpan(); - ParallelHelper.IterateRows( - workingRectangle, - configuration, - rows => + // Bulk conversion to RGB24 + this.pixelOpInstance.ToRgb24(pixelSpan, rgbSpan); + + for (int x = startX; x < endX; x++) + { + ulong sum = 0; + for (int y = startY; y < endY; y++) { - Span rgbSpan = tmpBuffer.GetSpan(); - uint sum; - for (int x = startX; x < endX; x++) + ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; + + sum += (ulong)(rgb.R + rgb.G + rgb.B); + + if (x != 0) + { + intImage[x - startX, y - startY] = intImage[x - startX - 1, y - startY] + sum; + } + else { - sum = 0; - for (int y = rows.Min; y < rows.Max; y++) - { - ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; - sum += (uint)(rgb.R + rgb.G + rgb.B); - - if (x > 0) - { - intImage[x - startX, y - startY] = intImage[x - 1 - startX, y - startY] + sum; - } - else - { - intImage[x - startX, y - startY] = sum; - } - } + intImage[x - startX, y - startY] = sum; } - }); + } + } - ParallelHelper.IterateRows( - workingRectangle, - configuration, - rows => + ushort x1, x2, y1, y2; + uint count = 0; + + for (int x = startX; x < endX; x++) + { + long sum = 0; + for (int y = startY; y < endY; y++) { - ushort x1, x2, y1, y2; - Span rgbSpan = tmpBuffer.GetSpan(); - long sum = 0; - uint count = 0; + ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; + + x1 = (ushort)Math.Max(x - startX - clusterSize + 1, 0); + x2 = (ushort)Math.Min(x - startX + clusterSize + 1, width - 1); + y1 = (ushort)Math.Max(y - startY - clusterSize + 1, 0); + y2 = (ushort)Math.Min(y - startY + clusterSize + 1, height - 1); + + count = (uint)((x2 - x1) * (y2 - y1)); + sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); - for (int x = startX; x < endX; x++) + if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.ThresholdLimit) { - for (int y = rows.Min; y < rows.Max; y++) - { - ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; - x1 = (ushort)Math.Max(x - clusterSize + 1 - startX, 0); - x2 = (ushort)Math.Min(x + clusterSize + 1 - startX, endX - startX - 1); - y1 = (ushort)Math.Max(y - clusterSize + 1 - startY, 0); - y2 = (ushort)Math.Min(y + clusterSize + 1 - startY, endY - startY - 1); - - count = (uint)((x2 - x1) * (y2 - y1)); - - sum = (long)(intImage[x2, y2] - intImage[x2, y1] - intImage[x1, y2] + intImage[x1, y1]); - - if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.ThresholdLimit) - { - source[x, y] = this.Lower; - } - else - { - source[x, y] = this.Upper; - } - } - } - }); + pixelSpan[(width * y) + x] = this.Lower; + } + else + { + pixelSpan[(width * y) + x] = this.Upper; + } + } + } } } } From 1f52c9d77c83ec06edb3a4afda5c4c85a9b30744 Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Tue, 30 Oct 2018 19:01:56 -0230 Subject: [PATCH 012/213] Fully working implementation --- .../AdaptiveThresholdProcessor.cs | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 030768e69b..4fb97aa9f8 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -92,29 +92,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Using pooled 2d buffer for integer image table and temp memory to hold Rgb24 converted pixel data using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height)) - using (IMemoryOwner bulkRgbBuf = configuration.MemoryAllocator.Allocate(width * height)) + using (IMemoryOwner tmpBuffer = configuration.MemoryAllocator.Allocate(width * height)) { // Defines the rectangle section of the image to work on Rectangle workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); - // TPixel span of the original image - Span pixelSpan = source.GetPixelSpan(); - - // RGB24 span of the converted pixel buffer - Span rgbSpan = bulkRgbBuf.GetSpan(); - - // Bulk conversion to RGB24 - this.pixelOpInstance.ToRgb24(pixelSpan, rgbSpan); + this.pixelOpInstance.ToRgb24(source.GetPixelSpan(), tmpBuffer.GetSpan()); for (int x = startX; x < endX; x++) { + Span rgbSpan = tmpBuffer.GetSpan(); ulong sum = 0; for (int y = startY; y < endY; y++) { ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; - sum += (ulong)(rgb.R + rgb.G + rgb.B); - + sum += (ulong)(rgb.R + rgb.G + rgb.G); if (x != 0) { intImage[x - startX, y - startY] = intImage[x - startX - 1, y - startY] + sum; @@ -126,34 +119,41 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization } } - ushort x1, x2, y1, y2; - uint count = 0; - - for (int x = startX; x < endX; x++) - { - long sum = 0; - for (int y = startY; y < endY; y++) + ParallelHelper.IterateRows( + workingRectangle, + configuration, + rows => { - ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; + Span rgbSpan = tmpBuffer.GetSpan(); + ushort x1, y1, x2, y2; + uint count = 0; + long sum = 0; - x1 = (ushort)Math.Max(x - startX - clusterSize + 1, 0); - x2 = (ushort)Math.Min(x - startX + clusterSize + 1, width - 1); - y1 = (ushort)Math.Max(y - startY - clusterSize + 1, 0); - y2 = (ushort)Math.Min(y - startY + clusterSize + 1, height - 1); - - count = (uint)((x2 - x1) * (y2 - y1)); - sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); - - if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.ThresholdLimit) + for (int x = startX; x < endX; x++) { - pixelSpan[(width * y) + x] = this.Lower; + for (int y = rows.Min; y < rows.Max; y++) + { + ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; + + x1 = (ushort)Math.Max(x - startX - clusterSize + 1, 0); + x2 = (ushort)Math.Min(x - startX + clusterSize + 1, width - 1); + y1 = (ushort)Math.Max(y - startY - clusterSize + 1, 0); + y2 = (ushort)Math.Min(y - startY + clusterSize + 1, height - 1); + + count = (uint)((x2 - x1) * (y2 - y1)); + sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); + + if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.ThresholdLimit) + { + source[x, y] = this.Lower; + } + else + { + source[x, y] = this.Upper; + } + } } - else - { - pixelSpan[(width * y) + x] = this.Upper; - } - } - } + }); } } } From 31e5d8d35d3153906abaf30ff499282a05850a8a Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Wed, 31 Oct 2018 12:45:56 -0230 Subject: [PATCH 013/213] Changed naming convention for threshold limit param --- .../Processing/AdaptiveThresholdExtensions.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs index 6c8795aa5d..33cf4b45be 100644 --- a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs +++ b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs @@ -23,12 +23,12 @@ namespace SixLabors.ImageSharp.Processing /// Applies Bradley Adaptive Threshold to the image. /// /// The image this method extends. - /// Threshold limit (0.0-1.0) to consider for binarization. + /// Threshold limit (0.0-1.0) to consider for binarization. /// The pixel format. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, float threshold) + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, float thresholdLimit) where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor(threshold)); + => source.ApplyProcessor(new AdaptiveThresholdProcessor(thresholdLimit)); /// /// Applies Bradley Adaptive Threshold to the image. @@ -48,12 +48,12 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// Upper (white) color for thresholding. /// Lower (black) color for thresholding - /// Threshold limit (0.0-1.0) to consider for binarization. + /// Threshold limit (0.0-1.0) to consider for binarization. /// The pixel format. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, float threshold) + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, float thresholdLimit) where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, threshold)); + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, thresholdLimit)); /// /// Applies Bradley Adaptive Threshold to the image. @@ -74,12 +74,12 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// Upper (white) color for thresholding. /// Lower (black) color for thresholding - /// Threshold limit (0.0-1.0) to consider for binarization. + /// Threshold limit (0.0-1.0) to consider for binarization. /// Rectangle region to apply the processor on. /// The pixel format. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, float threshold, Rectangle rectangle) + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, float thresholdLimit, Rectangle rectangle) where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, threshold), rectangle); + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, thresholdLimit), rectangle); } } \ No newline at end of file From 8610f5c6b4f7f91e5d2a6f884361be03f6e3a246 Mon Sep 17 00:00:00 2001 From: Simanto Rahman Date: Wed, 31 Oct 2018 12:46:26 -0230 Subject: [PATCH 014/213] Fixed a minor bug --- .../AdaptiveThresholdProcessor.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 4fb97aa9f8..2ad170e380 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -32,9 +32,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// /// Initializes a new instance of the class. /// - /// Threshold limit - public AdaptiveThresholdProcessor(float threshold) - : this(NamedColors.White, NamedColors.Black, threshold) + /// Threshold limit + public AdaptiveThresholdProcessor(float thresholdLimit) + : this(NamedColors.White, NamedColors.Black, thresholdLimit) { } @@ -48,14 +48,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// /// Color for upper threshold /// Color for lower threshold - /// Threshold limit - public AdaptiveThresholdProcessor(TPixel upper, TPixel lower, float threshold) + /// Threshold limit + public AdaptiveThresholdProcessor(TPixel upper, TPixel lower, float thresholdLimit) { this.pixelOpInstance = PixelOperations.Instance; this.Upper = upper; this.Lower = lower; - this.ThresholdLimit = threshold; + this.ThresholdLimit = thresholdLimit; } /// @@ -99,16 +99,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization this.pixelOpInstance.ToRgb24(source.GetPixelSpan(), tmpBuffer.GetSpan()); - for (int x = startX; x < endX; x++) + for (ushort x = startX; x < endX; x++) { Span rgbSpan = tmpBuffer.GetSpan(); ulong sum = 0; - for (int y = startY; y < endY; y++) + for (ushort y = startY; y < endY; y++) { ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; sum += (ulong)(rgb.R + rgb.G + rgb.G); - if (x != 0) + if (x - startX != 0) { intImage[x - startX, y - startY] = intImage[x - startX - 1, y - startY] + sum; } @@ -129,9 +129,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization uint count = 0; long sum = 0; - for (int x = startX; x < endX; x++) + for (ushort x = startX; x < endX; x++) { - for (int y = rows.Min; y < rows.Max; y++) + for (ushort y = (ushort)rows.Min; y < (ushort)rows.Max; y++) { ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization y2 = (ushort)Math.Min(y - startY + clusterSize + 1, height - 1); count = (uint)((x2 - x1) * (y2 - y1)); - sum = (long)(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1]); + sum = (long)Math.Min(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1], long.MaxValue); if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.ThresholdLimit) { From 9d62a2c989957e8ca67cdd2400f6dcd267db8324 Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Thu, 19 Sep 2019 09:30:13 -0700 Subject: [PATCH 015/213] Added: ability to skip unneeded chunks for optimization mode --- src/ImageSharp/Formats/Png/IPngEncoderOptions.cs | 5 +++++ src/ImageSharp/Formats/Png/PngEncoderCore.cs | 13 +++++++++---- src/ImageSharp/Formats/Png/PngEncoderOptions.cs | 6 ++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 87fd2582a5..0f416cb7b0 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -57,5 +57,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets a value indicating whether this instance should write an Adam7 interlaced image. /// PngInterlaceMode? InterlaceMethod { get; } + + /// + /// Gets a value indicating whether this instance should skip certain chunks to decrease file size + /// + bool Optimized { get; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 09575bb288..4442bdb0dd 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -155,10 +155,15 @@ namespace SixLabors.ImageSharp.Formats.Png this.WriteHeaderChunk(stream); this.WritePaletteChunk(stream, quantized); this.WriteTransparencyChunk(stream, pngMetadata); - this.WritePhysicalChunk(stream, metadata); - this.WriteGammaChunk(stream); - this.WriteExifChunk(stream, metadata); - this.WriteTextChunks(stream, pngMetadata); + + if (!this.options.Optimized) + { + this.WritePhysicalChunk(stream, metadata); + this.WriteGammaChunk(stream); + this.WriteExifChunk(stream, metadata); + this.WriteTextChunks(stream, pngMetadata); + } + this.WriteDataChunks(image.Frames.RootFrame, quantized, stream); this.WriteEndChunk(stream); stream.Flush(); diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index dd6c66cb7c..5d4be8f149 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -29,6 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.Quantizer = source.Quantizer; this.Threshold = source.Threshold; this.InterlaceMethod = source.InterlaceMethod; + this.Optimized = source.Optimized; } /// @@ -78,5 +79,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets or sets a value indicating whether this instance should write an Adam7 interlaced image. /// public PngInterlaceMode? InterlaceMethod { get; set; } + + /// + /// Gets or sets a value indicating whether this instance should skip certain chunks to decrease file size + /// + public bool Optimized { get; set; } } } From 69f01c3df5c9316988d20e7788c9ea707e8305f1 Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Thu, 19 Sep 2019 10:21:41 -0700 Subject: [PATCH 016/213] Update: forgot to implement Optimized property --- src/ImageSharp/Formats/Png/PngEncoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 3e46ad29ec..adad47f436 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -62,6 +62,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// public PngInterlaceMode? InterlaceMethod { get; set; } + /// + /// Gets a value indicating whether this instance should skip certain chunks to decrease file size + /// + public bool Optimized { get; } + /// /// Encodes the image to the specified stream from the . /// From 9ee2066713a99afc36cc0a3bb9dff116ba5fd0f6 Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Thu, 19 Sep 2019 11:22:37 -0700 Subject: [PATCH 017/213] Added: test + fixed optimized property --- src/ImageSharp/Formats/Png/PngEncoder.cs | 2 +- .../Formats/Png/PngEncoderTests.cs | 40 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index adad47f436..43d7f1ea68 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets a value indicating whether this instance should skip certain chunks to decrease file size /// - public bool Optimized { get; } + public bool Optimized { get; set; } /// /// Encodes the image to the specified stream from the . diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 2584391bb7..05a68a463b 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -195,6 +195,40 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Rgb, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.Rgb, PngBitDepth.Bit16)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit1)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit2)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit4)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit1)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit2)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit4)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb48, PngColorType.Grayscale, PngBitDepth.Bit16)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit16)] + public void WorksWithAllBitDepthsOptimized(TestImageProvider provider, PngColorType pngColorType, PngBitDepth pngBitDepth) + where TPixel : struct, IPixel + { + foreach (PngInterlaceMode interlaceMode in InterlaceMode) + { + TestPngEncoderCore( + provider, + pngColorType, + PngFilterMethod.Adaptive, + pngBitDepth, + interlaceMode, + appendPngColorType: true, + appendPixelType: true, + appendPngBitDepth: true, + optimized: true); + } + } + [Theory] [WithFile(TestImages.Png.Palette8Bpp, nameof(PaletteLargeOnly), PixelTypes.Rgba32)] public void PaletteColorType_WuQuantizer(TestImageProvider provider, int paletteSize) @@ -356,7 +390,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png bool appendPixelType = false, bool appendCompressionLevel = false, bool appendPaletteSize = false, - bool appendPngBitDepth = false) + bool appendPngBitDepth = false, + bool optimized = false) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -368,7 +403,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png CompressionLevel = compressionLevel, BitDepth = bitDepth, Quantizer = new WuQuantizer(paletteSize), - InterlaceMethod = interlaceMode + InterlaceMethod = interlaceMode, + Optimized = optimized, }; string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; From 8d9fbb78697075450a6692c706561057353ba65f Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Thu, 19 Sep 2019 16:52:56 -0700 Subject: [PATCH 018/213] Fixed property documentation + Optimized transparency --- src/ImageSharp/Formats/Png/PngEncoder.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 43d7f1ea68..5a79915de1 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Png public PngInterlaceMode? InterlaceMethod { get; set; } /// - /// Gets a value indicating whether this instance should skip certain chunks to decrease file size + /// Gets or sets a value indicating whether this instance should skip certain chunks to decrease file size /// public bool Optimized { get; set; } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 4442bdb0dd..8833389e7c 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); this.WriteHeaderChunk(stream); - this.WritePaletteChunk(stream, quantized); + this.WritePaletteChunk(stream, quantized, this.options.Optimized); this.WriteTransparencyChunk(stream, pngMetadata); if (!this.options.Optimized) @@ -552,7 +552,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing image data. /// The quantized frame. - private void WritePaletteChunk(Stream stream, IQuantizedFrame quantized) + /// If optimized make fully transparent pixels black. + private void WritePaletteChunk(Stream stream, IQuantizedFrame quantized, bool optimized) where TPixel : struct, IPixel { if (quantized == null) @@ -584,9 +585,9 @@ namespace SixLabors.ImageSharp.Formats.Png byte alpha = rgba.A; - Unsafe.Add(ref colorTableRef, offset) = rgba.R; - Unsafe.Add(ref colorTableRef, offset + 1) = rgba.G; - Unsafe.Add(ref colorTableRef, offset + 2) = rgba.B; + Unsafe.Add(ref colorTableRef, offset) = optimized && alpha == 0 ? (byte)0 : rgba.R; + Unsafe.Add(ref colorTableRef, offset + 1) = optimized && alpha == 0 ? (byte)0 : rgba.G; + Unsafe.Add(ref colorTableRef, offset + 2) = optimized && alpha == 0 ? (byte)0 : rgba.B; if (alpha > this.options.Threshold) { From 81bc719c211029cfe2f5b6fe9e0a3ee769cb165c Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Fri, 20 Sep 2019 07:31:55 -0700 Subject: [PATCH 019/213] Update: expanded optimize options --- .../Formats/Png/IPngEncoderOptions.cs | 4 +- src/ImageSharp/Formats/Png/PngEncoder.cs | 4 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 37 +++++++++++--- .../Formats/Png/PngEncoderOptions.cs | 6 +-- .../Formats/Png/PngOptimizeMethod.cs | 49 +++++++++++++++++++ 5 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/PngOptimizeMethod.cs diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 0f416cb7b0..38c3484c81 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -59,8 +59,8 @@ namespace SixLabors.ImageSharp.Formats.Png PngInterlaceMode? InterlaceMethod { get; } /// - /// Gets a value indicating whether this instance should skip certain chunks to decrease file size + /// Gets the optimize method. /// - bool Optimized { get; } + PngOptimizeMethod? OptimizeMethod { get; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 5a79915de1..16bd538c31 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -63,9 +63,9 @@ namespace SixLabors.ImageSharp.Formats.Png public PngInterlaceMode? InterlaceMethod { get; set; } /// - /// Gets or sets a value indicating whether this instance should skip certain chunks to decrease file size + /// Gets or sets the optimize method. /// - public bool Optimized { get; set; } + public PngOptimizeMethod? OptimizeMethod { get; set; } /// /// Encodes the image to the specified stream from the . diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 8833389e7c..02bb67c728 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -153,14 +153,26 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); this.WriteHeaderChunk(stream); - this.WritePaletteChunk(stream, quantized, this.options.Optimized); + this.WritePaletteChunk(stream, quantized, this.options.OptimizeMethod); this.WriteTransparencyChunk(stream, pngMetadata); - if (!this.options.Optimized) + if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressPhysicalChunk) != PngOptimizeMethod.SuppressPhysicalChunk) { this.WritePhysicalChunk(stream, metadata); + } + + if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressGammaChunk) != PngOptimizeMethod.SuppressGammaChunk) + { this.WriteGammaChunk(stream); + } + + if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressExifChunk) != PngOptimizeMethod.SuppressExifChunk) + { this.WriteExifChunk(stream, metadata); + } + + if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressTextChunks) != PngOptimizeMethod.SuppressTextChunks) + { this.WriteTextChunks(stream, pngMetadata); } @@ -552,8 +564,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing image data. /// The quantized frame. - /// If optimized make fully transparent pixels black. - private void WritePaletteChunk(Stream stream, IQuantizedFrame quantized, bool optimized) + /// The optimize method. + private void WritePaletteChunk(Stream stream, IQuantizedFrame quantized, PngOptimizeMethod? optimizeMethod) where TPixel : struct, IPixel { if (quantized == null) @@ -576,6 +588,8 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba = default; + bool makeTransparentBlack = ((optimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.MakeTransparentBlack) == PngOptimizeMethod.MakeTransparentBlack; + for (int i = 0; i < paletteLength; i++) { if (quantizedSpan.IndexOf((byte)i) > -1) @@ -585,9 +599,18 @@ namespace SixLabors.ImageSharp.Formats.Png byte alpha = rgba.A; - Unsafe.Add(ref colorTableRef, offset) = optimized && alpha == 0 ? (byte)0 : rgba.R; - Unsafe.Add(ref colorTableRef, offset + 1) = optimized && alpha == 0 ? (byte)0 : rgba.G; - Unsafe.Add(ref colorTableRef, offset + 2) = optimized && alpha == 0 ? (byte)0 : rgba.B; + if (makeTransparentBlack && alpha == 0) + { + Unsafe.Add(ref colorTableRef, offset) = 0; + Unsafe.Add(ref colorTableRef, offset + 1) = 0; + Unsafe.Add(ref colorTableRef, offset + 2) = 0; + } + else + { + Unsafe.Add(ref colorTableRef, offset) = rgba.R; + Unsafe.Add(ref colorTableRef, offset + 1) = rgba.G; + Unsafe.Add(ref colorTableRef, offset + 2) = rgba.B; + } if (alpha > this.options.Threshold) { diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index 5d4be8f149..89d7b0d5ef 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.Quantizer = source.Quantizer; this.Threshold = source.Threshold; this.InterlaceMethod = source.InterlaceMethod; - this.Optimized = source.Optimized; + this.OptimizeMethod = source.OptimizeMethod; } /// @@ -81,8 +81,8 @@ namespace SixLabors.ImageSharp.Formats.Png public PngInterlaceMode? InterlaceMethod { get; set; } /// - /// Gets or sets a value indicating whether this instance should skip certain chunks to decrease file size + /// Gets or sets a the optimize method. /// - public bool Optimized { get; set; } + public PngOptimizeMethod? OptimizeMethod { get; set; } } } diff --git a/src/ImageSharp/Formats/Png/PngOptimizeMethod.cs b/src/ImageSharp/Formats/Png/PngOptimizeMethod.cs new file mode 100644 index 0000000000..7ad6646380 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngOptimizeMethod.cs @@ -0,0 +1,49 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// Provides enumeration of available PNG optimization methods. + /// + [Flags] + public enum PngOptimizeMethod + { + /// + /// With the None filter, the scanline is transmitted unmodified. + /// + None = 0, + + /// + /// Suppress the physical dimension information chunk. + /// + SuppressPhysicalChunk = 1, + + /// + /// Suppress the gamma information chunk. + /// + SuppressGammaChunk = 2, + + /// + /// Suppress the eXIf chunk. + /// + SuppressExifChunk = 4, + + /// + /// Suppress the tTXt, iTXt or zTXt chunk. + /// + SuppressTextChunks = 8, + + /// + /// Make funlly transparent pixels black. + /// + MakeTransparentBlack = 16, + + /// + /// All possible optimizations. + /// + All = 31, + } +} From fc8f5e3eaa0418352a91f1e1ae15d7a84c3b78ba Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Fri, 20 Sep 2019 07:57:53 -0700 Subject: [PATCH 020/213] Update: transparent pixels to black before quantization --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 56 +++++++++++++------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 02bb67c728..12a681feab 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -147,13 +147,43 @@ namespace SixLabors.ImageSharp.Formats.Png ImageMetadata metadata = image.Metadata; PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); - IQuantizedFrame quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, image); - this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, image, quantized); + + IQuantizedFrame quantized; + + if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.MakeTransparentBlack) == PngOptimizeMethod.MakeTransparentBlack) + { + using (Image tempImage = image.Clone()) + { + Span span = tempImage.GetPixelSpan(); + foreach (TPixel pixel in span) + { + Rgba32 rgba32 = Rgba32.Transparent; + pixel.ToRgba32(ref rgba32); + + if (rgba32.A == 0) + { + rgba32.R = 0; + rgba32.G = 0; + rgba32.B = 0; + } + + pixel.FromRgba32(rgba32); + } + + quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, tempImage); + this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, tempImage, quantized); + } + } + else + { + quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, image); + this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, image, quantized); + } stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); this.WriteHeaderChunk(stream); - this.WritePaletteChunk(stream, quantized, this.options.OptimizeMethod); + this.WritePaletteChunk(stream, quantized); this.WriteTransparencyChunk(stream, pngMetadata); if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressPhysicalChunk) != PngOptimizeMethod.SuppressPhysicalChunk) @@ -564,8 +594,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing image data. /// The quantized frame. - /// The optimize method. - private void WritePaletteChunk(Stream stream, IQuantizedFrame quantized, PngOptimizeMethod? optimizeMethod) + private void WritePaletteChunk(Stream stream, IQuantizedFrame quantized) where TPixel : struct, IPixel { if (quantized == null) @@ -588,8 +617,6 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba = default; - bool makeTransparentBlack = ((optimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.MakeTransparentBlack) == PngOptimizeMethod.MakeTransparentBlack; - for (int i = 0; i < paletteLength; i++) { if (quantizedSpan.IndexOf((byte)i) > -1) @@ -599,18 +626,9 @@ namespace SixLabors.ImageSharp.Formats.Png byte alpha = rgba.A; - if (makeTransparentBlack && alpha == 0) - { - Unsafe.Add(ref colorTableRef, offset) = 0; - Unsafe.Add(ref colorTableRef, offset + 1) = 0; - Unsafe.Add(ref colorTableRef, offset + 2) = 0; - } - else - { - Unsafe.Add(ref colorTableRef, offset) = rgba.R; - Unsafe.Add(ref colorTableRef, offset + 1) = rgba.G; - Unsafe.Add(ref colorTableRef, offset + 2) = rgba.B; - } + Unsafe.Add(ref colorTableRef, offset) = rgba.R; + Unsafe.Add(ref colorTableRef, offset + 1) = rgba.G; + Unsafe.Add(ref colorTableRef, offset + 2) = rgba.B; if (alpha > this.options.Threshold) { From ba08c64755ddea5cdbc02669ba11dac7b5f68e10 Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Fri, 20 Sep 2019 08:21:45 -0700 Subject: [PATCH 021/213] Fixed tests --- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 05a68a463b..c72dbe2891 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -225,14 +225,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png appendPngColorType: true, appendPixelType: true, appendPngBitDepth: true, - optimized: true); + optimizeMethod: PngOptimizeMethod.All); } } [Theory] [WithFile(TestImages.Png.Palette8Bpp, nameof(PaletteLargeOnly), PixelTypes.Rgba32)] public void PaletteColorType_WuQuantizer(TestImageProvider provider, int paletteSize) - where TPixel : struct, IPixel + where TPixel : struct, IPixel { foreach (PngInterlaceMode interlaceMode in InterlaceMode) { @@ -391,7 +391,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png bool appendCompressionLevel = false, bool appendPaletteSize = false, bool appendPngBitDepth = false, - bool optimized = false) + PngOptimizeMethod optimizeMethod = PngOptimizeMethod.None) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -404,7 +404,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png BitDepth = bitDepth, Quantizer = new WuQuantizer(paletteSize), InterlaceMethod = interlaceMode, - Optimized = optimized, + OptimizeMethod = optimizeMethod, }; string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; From f8c5277fb4012da6967cc84a0c83c96533cf43d2 Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Fri, 20 Sep 2019 09:32:39 -0700 Subject: [PATCH 022/213] Fixed transparency update --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 12a681feab..d8be4c80ac 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -155,19 +155,17 @@ namespace SixLabors.ImageSharp.Formats.Png using (Image tempImage = image.Clone()) { Span span = tempImage.GetPixelSpan(); - foreach (TPixel pixel in span) + for (int i = 0; i < span.Length; i++) { - Rgba32 rgba32 = Rgba32.Transparent; - pixel.ToRgba32(ref rgba32); - + Rgba32 rgba32 = default; + span[i].ToRgba32(ref rgba32); if (rgba32.A == 0) { rgba32.R = 0; rgba32.G = 0; rgba32.B = 0; } - - pixel.FromRgba32(rgba32); + span[i].FromRgba32(rgba32); } quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, tempImage); From 6e3e4ce19fd8573a736bea67cd6b493dff7a85d6 Mon Sep 17 00:00:00 2001 From: Peter Tribe Date: Fri, 20 Sep 2019 10:52:42 -0700 Subject: [PATCH 023/213] Fixed formatting --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index d8be4c80ac..a3cc1d0187 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -159,12 +159,14 @@ namespace SixLabors.ImageSharp.Formats.Png { Rgba32 rgba32 = default; span[i].ToRgba32(ref rgba32); + if (rgba32.A == 0) { rgba32.R = 0; rgba32.G = 0; rgba32.B = 0; } + span[i].FromRgba32(rgba32); } From 60008fc740f83c62aefd86e6dd77f4e5cc985fa8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 26 Jan 2020 22:16:04 +0100 Subject: [PATCH 024/213] use only netcoreapp3.1 --- src/ImageSharp/ImageSharp.csproj | 3 ++- tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 3 ++- .../ImageSharp.Tests.ProfilingSandbox.csproj | 3 ++- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 0fd449d90f..f503ea64a0 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -10,7 +10,8 @@ $(packageversion) 0.0.1 - netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 + + netcoreapp3.1 true true diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 60b1fde8e0..198f2fb76f 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -5,7 +5,8 @@ ImageSharp.Benchmarks Exe SixLabors.ImageSharp.Benchmarks - netcoreapp3.1;netcoreapp2.1;net472 + + netcoreapp3.1 false false diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index 99269e339a..9ac20c0781 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -8,7 +8,8 @@ false SixLabors.ImageSharp.Tests.ProfilingSandbox win7-x64 - netcoreapp3.1;netcoreapp2.1;net472 + + netcoreapp3.1 SixLabors.ImageSharp.Tests.ProfilingSandbox.Program false diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 34cdca49a1..fdefa38e78 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,7 +2,8 @@ - netcoreapp3.1;netcoreapp2.1;net472 + + netcoreapp3.1 True True SixLabors.ImageSharp.Tests From bcf50cafba6810ad293619632e4ac388d96f72e7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 30 Jan 2020 13:39:55 +1100 Subject: [PATCH 025/213] Don't use ToArray() when we don't need to. --- Directory.Build.props | 28 ++++++++++++++-------------- src/ImageSharp/ImageExtensions.cs | 22 ++++++++++++++++++++-- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 604153f976..def231a7ae 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -31,27 +31,27 @@ - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE;SUPPORTS_BASE64SPAN - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE;SUPPORTS_BASE64SPAN - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_CODECOVERAGE;SUPPORTS_BASE64SPAN $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 6cdc948d40..7f753c05a6 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Collections.Generic; using System.IO; using System.Text; @@ -115,8 +116,25 @@ namespace SixLabors.ImageSharp using (var stream = new MemoryStream()) { source.Save(stream, format); - stream.Flush(); - return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; + + // Always available. + stream.TryGetBuffer(out ArraySegment buffer); + +#if !SUPPORTS_BASE64SPAN + + byte[] sharedBuffer = ArrayPool.Shared.Rent(buffer.Count); + try + { + buffer.AsSpan().CopyTo(sharedBuffer); + return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(sharedBuffer)}"; + } + finally + { + ArrayPool.Shared.Return(sharedBuffer); + } +#else + return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(buffer)}"; +#endif } } } From c69eb2bee020eae87d69d6237705e54ce9add36a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 28 Feb 2020 15:45:16 +1100 Subject: [PATCH 026/213] Simplify API --- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 +- .../Processors/Dithering/ErrorDither.cs | 30 ++++--- .../Processors/Dithering/IDither.cs | 21 ++--- .../IPaletteDitherImageProcessor{TPixel}.cs | 39 ++++++++++ .../Processors/Dithering/OrderedDither.cs | 77 ++++++++---------- .../PaletteDitherProcessor{TPixel}.cs | 78 ++++++++++++------- .../Quantization/EuclideanPixelMap{TPixel}.cs | 7 +- .../Quantization/FrameQuantizerExtensions.cs | 34 ++++---- .../Quantization/IFrameQuantizer{TPixel}.cs | 6 +- .../Quantization/QuantizedFrame{TPixel}.cs | 11 +-- 11 files changed, 170 insertions(+), 139 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 1b3e0228a8..1b7d2e5be9 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -360,7 +360,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = image.Height - 1; y >= 0; y--) { - ReadOnlySpan pixelSpan = quantized.GetRowSpan(y); + ReadOnlySpan pixelSpan = quantized.GetPixelRowSpan(y); stream.Write(pixelSpan); for (int i = 0; i < this.padding; i++) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 5f14d483b9..f8226fc3fc 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -380,7 +380,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.bitDepth < 8) { - PngEncoderHelpers.ScaleDownFrom8BitArray(quantized.GetRowSpan(row), this.currentScanline.GetSpan(), this.bitDepth); + PngEncoderHelpers.ScaleDownFrom8BitArray(quantized.GetPixelRowSpan(row), this.currentScanline.GetSpan(), this.bitDepth); } else { @@ -987,7 +987,7 @@ namespace SixLabors.ImageSharp.Formats.Png row += Adam7.RowIncrement[pass]) { // collect data - ReadOnlySpan srcRow = quantized.GetRowSpan(row); + ReadOnlySpan srcRow = quantized.GetPixelRowSpan(row); for (int col = startCol, i = 0; col < width; col += Adam7.ColumnIncrement[pass]) diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 079a22ecce..2d7e138f47 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -89,29 +89,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering [MethodImpl(InliningOptions.ShortMethod)] public void ApplyQuantizationDither( ref TFrameQuantizer quantizer, - ReadOnlyMemory palette, ImageFrame source, - Memory output, + QuantizedFrame destination, Rectangle bounds) where TFrameQuantizer : struct, IFrameQuantizer where TPixel : struct, IPixel { - Span outputSpan = output.Span; - ReadOnlySpan paletteSpan = palette.Span; - int width = bounds.Width; + ReadOnlySpan paletteSpan = destination.Palette.Span; int offsetY = bounds.Top; int offsetX = bounds.Left; float scale = quantizer.Options.DitherScale; for (int y = bounds.Top; y < bounds.Bottom; y++) { - Span row = source.GetPixelRowSpan(y); - int rowStart = (y - offsetY) * width; + Span sourceRow = source.GetPixelRowSpan(y); + Span destinationRow = destination.GetPixelRowSpan(y - offsetY); for (int x = bounds.Left; x < bounds.Right; x++) { - TPixel sourcePixel = row[x]; - outputSpan[rowStart + x - offsetX] = quantizer.GetQuantizedColor(sourcePixel, paletteSpan, out TPixel transformed); + TPixel sourcePixel = sourceRow[x]; + destinationRow[x - offsetX] = quantizer.GetQuantizedColor(sourcePixel, paletteSpan, out TPixel transformed); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); } } @@ -119,23 +116,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyPaletteDither( - Configuration configuration, - ReadOnlyMemory palette, + public void ApplyPaletteDither( + in TPaletteDitherImageProcessor processor, ImageFrame source, - Rectangle bounds, - float scale) + Rectangle bounds) + where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor where TPixel : struct, IPixel { - var pixelMap = new EuclideanPixelMap(palette); - + float scale = processor.DitherScale; + ReadOnlySpan palette = processor.Palette.Span; for (int y = bounds.Top; y < bounds.Bottom; y++) { Span row = source.GetPixelRowSpan(y); for (int x = bounds.Left; x < bounds.Right; x++) { TPixel sourcePixel = row[x]; - pixelMap.GetClosestColor(sourcePixel, out TPixel transformed); + TPixel transformed = processor.GetPaletteColor(sourcePixel, palette); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); row[x] = transformed; } diff --git a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs index fc8ee32f77..4f2b93efb8 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -19,15 +18,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// The type of frame quantizer. /// The pixel format. /// The frame quantizer. - /// The quantized palette. /// The source image. - /// The output target + /// The destination quantized frame. /// The region of interest bounds. void ApplyQuantizationDither( ref TFrameQuantizer quantizer, - ReadOnlyMemory palette, ImageFrame source, - Memory output, + QuantizedFrame destination, Rectangle bounds) where TFrameQuantizer : struct, IFrameQuantizer where TPixel : struct, IPixel; @@ -36,18 +33,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// Transforms the image frame applying a dither matrix. /// This method should be treated as destructive, altering the input pixels. /// + /// The type of palette dithering processor. /// The pixel format. - /// The configuration. - /// The quantized palette. + /// The palette dithering processor. /// The source image. /// The region of interest bounds. - /// The dithering scale used to adjust the amount of dither. Range 0..1. - void ApplyPaletteDither( - Configuration configuration, - ReadOnlyMemory palette, + void ApplyPaletteDither( + in TPaletteDitherImageProcessor processor, ImageFrame source, - Rectangle bounds, - float scale) + Rectangle bounds) + where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs new file mode 100644 index 0000000000..73a6c8f4f4 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Dithering +{ + /// + /// Implements an algorithm to alter the pixels of an image via palette dithering. + /// + /// The pixel format. + public interface IPaletteDitherImageProcessor + where TPixel : struct, IPixel + { + /// + /// Gets the configration instance to use when performing operations. + /// + public Configuration Configuration { get; } + + /// + /// Gets the dithering palette. + /// + ReadOnlyMemory Palette { get; } + + /// + /// Gets the dithering scale used to adjust the amount of dither. Range 0..1. + /// + float DitherScale { get; } + + /// + /// Returns the color from the dithering palette corresponding to the given color. + /// + /// The color to match. + /// The output color palette. + /// The match. + TPixel GetPaletteColor(TPixel color, ReadOnlySpan palette); + } +} diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 69e323bd53..854898e623 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -105,9 +105,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering [MethodImpl(InliningOptions.ShortMethod)] public void ApplyQuantizationDither( ref TFrameQuantizer quantizer, - ReadOnlyMemory palette, ImageFrame source, - Memory output, + QuantizedFrame destination, Rectangle bounds) where TFrameQuantizer : struct, IFrameQuantizer where TPixel : struct, IPixel @@ -116,10 +115,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering ref quantizer, in Unsafe.AsRef(this), source, - output, - bounds, - palette, - ImageMaths.GetBitsNeededForColorDepth(palette.Span.Length)); + destination, + bounds); ParallelRowIterator.IterateRows( quantizer.Configuration, @@ -129,24 +126,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// [MethodImpl(InliningOptions.ShortMethod)] - public void ApplyPaletteDither( - Configuration configuration, - ReadOnlyMemory palette, + public void ApplyPaletteDither( + in TPaletteDitherImageProcessor processor, ImageFrame source, - Rectangle bounds, - float scale) + Rectangle bounds) + where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor where TPixel : struct, IPixel { - var ditherOperation = new PaletteDitherRowIntervalOperation( + var ditherOperation = new PaletteDitherRowIntervalOperation( + in processor, in Unsafe.AsRef(this), source, - bounds, - palette, - scale, - ImageMaths.GetBitsNeededForColorDepth(palette.Span.Length)); + bounds); ParallelRowIterator.IterateRows( - configuration, + processor.Configuration, bounds, in ditherOperation); } @@ -207,7 +201,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering private readonly TFrameQuantizer quantizer; private readonly OrderedDither dither; private readonly ImageFrame source; - private readonly Memory output; + private readonly QuantizedFrame destination; private readonly Rectangle bounds; private readonly ReadOnlyMemory palette; private readonly int bitDepth; @@ -217,84 +211,79 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering ref TFrameQuantizer quantizer, in OrderedDither dither, ImageFrame source, - Memory output, - Rectangle bounds, - ReadOnlyMemory palette, - int bitDepth) + QuantizedFrame destination, + Rectangle bounds) { this.quantizer = quantizer; this.dither = dither; this.source = source; - this.output = output; + this.destination = destination; this.bounds = bounds; - this.palette = palette; - this.bitDepth = bitDepth; + this.palette = destination.Palette; + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(destination.Palette.Span.Length); } [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { ReadOnlySpan paletteSpan = this.palette.Span; - Span outputSpan = this.output.Span; - int width = this.bounds.Width; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; float scale = this.quantizer.Options.DitherScale; for (int y = rows.Min; y < rows.Max; y++) { - Span row = this.source.GetPixelRowSpan(y); - int rowStart = (y - offsetY) * width; + Span sourceRow = this.source.GetPixelRowSpan(y); + Span destinationRow = this.destination.GetPixelRowSpan(y - offsetY); - // TODO: This can be a bulk operation. for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - TPixel dithered = this.dither.Dither(row[x], x, y, this.bitDepth, scale); - outputSpan[rowStart + x - offsetX] = this.quantizer.GetQuantizedColor(dithered, paletteSpan, out TPixel _); + TPixel dithered = this.dither.Dither(sourceRow[x], x, y, this.bitDepth, scale); + destinationRow[x - offsetX] = this.quantizer.GetQuantizedColor(dithered, paletteSpan, out TPixel _); } } } } - private readonly struct PaletteDitherRowIntervalOperation : IRowIntervalOperation + private readonly struct PaletteDitherRowIntervalOperation : IRowIntervalOperation + where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor where TPixel : struct, IPixel { + private readonly TPaletteDitherImageProcessor processor; private readonly OrderedDither dither; private readonly ImageFrame source; private readonly Rectangle bounds; - private readonly EuclideanPixelMap pixelMap; private readonly float scale; private readonly int bitDepth; [MethodImpl(InliningOptions.ShortMethod)] public PaletteDitherRowIntervalOperation( + in TPaletteDitherImageProcessor processor, in OrderedDither dither, ImageFrame source, - Rectangle bounds, - ReadOnlyMemory palette, - float scale, - int bitDepth) + Rectangle bounds) { + this.processor = processor; this.dither = dither; this.source = source; this.bounds = bounds; - this.pixelMap = new EuclideanPixelMap(palette); - this.scale = scale; - this.bitDepth = bitDepth; + this.scale = processor.DitherScale; + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(processor.Palette.Span.Length); } [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { + ReadOnlySpan paletteSpan = this.processor.Palette.Span; for (int y = rows.Min; y < rows.Max; y++) { Span row = this.source.GetPixelRowSpan(y); for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - TPixel dithered = this.dither.Dither(row[x], x, y, this.bitDepth, this.scale); - this.pixelMap.GetClosestColor(dithered, out TPixel transformed); - row[x] = transformed; + ref TPixel sourcePixel = ref row[x]; + TPixel dithered = this.dither.Dither(sourcePixel, x, y, this.bitDepth, this.scale); + sourcePixel = this.processor.GetPaletteColor(dithered, paletteSpan); } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 118352ec39..04351d34ff 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -3,7 +3,9 @@ using System; using System.Buffers; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Processing.Processors.Dithering { @@ -14,11 +16,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering internal sealed class PaletteDitherProcessor : ImageProcessor where TPixel : struct, IPixel { - private readonly int paletteLength; + private readonly DitherProcessor ditherProcessor; private readonly IDither dither; - private readonly float ditherScale; - private readonly ReadOnlyMemory sourcePalette; - private IMemoryOwner palette; + private IMemoryOwner paletteMemory; private bool isDisposed; /// @@ -31,37 +31,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public PaletteDitherProcessor(Configuration configuration, PaletteDitherProcessor definition, Image source, Rectangle sourceRectangle) : base(configuration, source, sourceRectangle) { - this.paletteLength = definition.Palette.Span.Length; this.dither = definition.Dither; - this.ditherScale = definition.DitherScale; - this.sourcePalette = definition.Palette; - } - /// - protected override void OnFrameApply(ImageFrame source) - { - var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); + ReadOnlySpan sourcePalette = definition.Palette.Span; + this.paletteMemory = this.Configuration.MemoryAllocator.Allocate(sourcePalette.Length); + Color.ToPixel(this.Configuration, sourcePalette, this.paletteMemory.Memory.Span); - this.dither.ApplyPaletteDither( + this.ditherProcessor = new DitherProcessor( this.Configuration, - this.palette.Memory, - source, - interest, - this.ditherScale); + this.paletteMemory.Memory, + definition.DitherScale); } /// - protected override void BeforeFrameApply(ImageFrame source) + protected override void OnFrameApply(ImageFrame source) { - // Lazy init palettes: - if (this.palette is null) - { - this.palette = this.Configuration.MemoryAllocator.Allocate(this.paletteLength); - ReadOnlySpan sourcePalette = this.sourcePalette.Span; - Color.ToPixel(this.Configuration, sourcePalette, this.palette.Memory.Span); - } - - base.BeforeFrameApply(source); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); + this.dither.ApplyPaletteDither(in this.ditherProcessor, source, interest); } /// @@ -74,13 +60,47 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering if (disposing) { - this.palette?.Dispose(); + this.paletteMemory?.Dispose(); } - this.palette = null; + this.paletteMemory = null; this.isDisposed = true; base.Dispose(disposing); } + + /// + /// Used to allow inlining of calls to + /// . + /// + private readonly struct DitherProcessor : IPaletteDitherImageProcessor + { + private readonly EuclideanPixelMap pixelMap; + + [MethodImpl(InliningOptions.ShortMethod)] + public DitherProcessor( + Configuration configuration, + ReadOnlyMemory palette, + float ditherScale) + { + this.Configuration = configuration; + this.pixelMap = new EuclideanPixelMap(palette); + this.Palette = palette; + this.DitherScale = ditherScale; + } + + public Configuration Configuration { get; } + + public ReadOnlyMemory Palette { get; } + + public float DitherScale { get; } + + [MethodImpl(InliningOptions.ShortMethod)] + public TPixel GetPaletteColor(TPixel color, ReadOnlySpan palette) + { + this.pixelMap.GetClosestColor(color, out TPixel match); + return match; + } + } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index a5e8d70b0d..720923a161 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -24,6 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Initializes a new instance of the struct. /// /// The color palette to map from. + [MethodImpl(InliningOptions.ShortMethod)] public EuclideanPixelMap(ReadOnlyMemory palette) { Guard.MustBeGreaterThan(palette.Length, 0, nameof(palette)); @@ -40,7 +41,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } /// - public ReadOnlyMemory Palette { get; } + public ReadOnlyMemory Palette + { + [MethodImpl(InliningOptions.ShortMethod)] + get; + } /// public override bool Equals(object obj) diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs index 5b49fe9e86..7bf7e9b35e 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs @@ -41,18 +41,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization MemoryAllocator memoryAllocator = quantizer.Configuration.MemoryAllocator; var quantizedFrame = new QuantizedFrame(memoryAllocator, interest.Width, interest.Height, palette); - Memory output = quantizedFrame.GetWritablePixelMemory(); if (quantizer.Options.Dither is null) { - SecondPass(ref quantizer, source, interest, output, palette); + SecondPass(ref quantizer, source, quantizedFrame, interest); } else { // We clone the image as we don't want to alter the original via error diffusion based dithering. using (ImageFrame clone = source.Clone()) { - SecondPass(ref quantizer, clone, interest, output, palette); + SecondPass(ref quantizer, clone, quantizedFrame, interest); } } @@ -63,9 +62,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private static void SecondPass( ref TFrameQuantizer quantizer, ImageFrame source, - Rectangle bounds, - Memory output, - ReadOnlyMemory palette) + QuantizedFrame destination, + Rectangle bounds) where TFrameQuantizer : struct, IFrameQuantizer where TPixel : struct, IPixel { @@ -73,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (dither is null) { - var operation = new RowIntervalOperation(quantizer, source, output, bounds, palette); + var operation = new RowIntervalOperation(quantizer, source, destination, bounds); ParallelRowIterator.IterateRows( quantizer.Configuration, bounds, @@ -82,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return; } - dither.ApplyQuantizationDither(ref quantizer, palette, source, output, bounds); + dither.ApplyQuantizationDither(ref quantizer, source, destination, bounds); } private readonly struct RowIntervalOperation : IRowIntervalOperation @@ -91,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { private readonly TFrameQuantizer quantizer; private readonly ImageFrame source; - private readonly Memory output; + private readonly QuantizedFrame destination; private readonly Rectangle bounds; private readonly ReadOnlyMemory palette; @@ -99,35 +97,31 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public RowIntervalOperation( in TFrameQuantizer quantizer, ImageFrame source, - Memory output, - Rectangle bounds, - ReadOnlyMemory palette) + QuantizedFrame destination, + Rectangle bounds) { this.quantizer = quantizer; this.source = source; - this.output = output; + this.destination = destination; this.bounds = bounds; - this.palette = palette; + this.palette = destination.Palette; } [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { ReadOnlySpan paletteSpan = this.palette.Span; - Span outputSpan = this.output.Span; - int width = this.bounds.Width; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; for (int y = rows.Min; y < rows.Max; y++) { - Span row = this.source.GetPixelRowSpan(y); - int rowStart = (y - offsetY) * width; + Span sourceRow = this.source.GetPixelRowSpan(y); + Span destinationRow = this.destination.GetPixelRowSpan(y - offsetY); - // TODO: This can be a bulk operation. for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - outputSpan[rowStart + x - offsetX] = this.quantizer.GetQuantizedColor(row[x], paletteSpan, out TPixel _); + destinationRow[x - offsetX] = this.quantizer.GetQuantizedColor(sourceRow[x], paletteSpan, out TPixel _); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index d3091c3b01..fdf4ab7a6a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -31,9 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// A representing a quantized version of the source frame pixels. /// - QuantizedFrame QuantizeFrame( - ImageFrame source, - Rectangle bounds); + QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds); /// /// Builds the quantized palette from the given image frame and bounds. @@ -44,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds); /// - /// Returns the index and color from the quantized palette corresponding to the give to the given color. + /// Returns the index and color from the quantized palette corresponding to the given color. /// /// The color to match. /// The output color palette. diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index fccc799bb9..93569a6ced 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -57,16 +57,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlySpan GetPixelSpan() => this.pixels.GetSpan(); + public Span GetPixelSpan() => this.pixels.GetSpan(); /// /// Gets the representation of the pixels as a of contiguous memory /// at row beginning from the the first pixel on that row. /// /// The row. - /// The pixel row as a . + /// The pixel row as a . [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlySpan GetRowSpan(int rowIndex) + public Span GetPixelRowSpan(int rowIndex) => this.GetPixelSpan().Slice(rowIndex * this.Width, this.Width); /// @@ -82,10 +82,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.pixels = null; this.Palette = null; } - - /// - /// Get the non-readonly memory of pixel data so can fill it. - /// - internal Memory GetWritablePixelMemory() => this.pixels.Memory; } } From 9d73689f5357e651ae72fdb3c853a79d4d4959a6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 28 Feb 2020 16:00:11 +1100 Subject: [PATCH 027/213] Update IPaletteDitherImageProcessor{TPixel}.cs --- .../Dithering/IPaletteDitherImageProcessor{TPixel}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs index 73a6c8f4f4..3e4bf4d836 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// The pixel format. public interface IPaletteDitherImageProcessor - where TPixel : struct, IPixel + where TPixel : unmanaged, IPixel { /// /// Gets the configration instance to use when performing operations. From d951fd9f74bd296b54e3cc5101ad7aa84ddb4bff Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 29 Feb 2020 02:39:19 +0100 Subject: [PATCH 028/213] tweak profiling benchmarks --- .../Program.cs | 14 ++++++--- .../JpegProfilingBenchmarks.cs | 31 +++++++++++-------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs b/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs index f041e16eb5..a94d0ed83f 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs +++ b/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs @@ -7,6 +7,10 @@ using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; using SixLabors.ImageSharp.Tests.ProfilingBenchmarks; using Xunit.Abstractions; +// in this file, comments are used for disabling stuff for local execution +#pragma warning disable SA1515 +#pragma warning disable SA1512 + namespace SixLabors.ImageSharp.Tests.ProfilingSandbox { public class Program @@ -28,10 +32,9 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox public static void Main(string[] args) { // RunJpegColorProfilingTests(); - - // RunDecodeJpegProfilingTests(); + RunDecodeJpegProfilingTests(); // RunToVector4ProfilingTest(); - RunResizeProfilingTest(); + // RunResizeProfilingTest(); Console.ReadLine(); } @@ -61,8 +64,11 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; - benchmarks.DecodeJpeg(fileName); + int executionCount = (int)data[1]; + benchmarks.DecodeJpeg(fileName, executionCount); } + + Console.WriteLine("DONE."); } } } diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index d0158e5019..987de29ea9 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -13,6 +13,9 @@ using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; +// in this file, comments are used for disabling stuff for local execution +#pragma warning disable SA1515 + namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { public class JpegProfilingBenchmarks : MeasureFixture @@ -22,24 +25,28 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { } - public static readonly TheoryData DecodeJpegData = new TheoryData + public static readonly TheoryData DecodeJpegData = new TheoryData { - TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, - TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, - TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, - TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, - TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, - TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + { TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, 20 }, + { TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, 20 }, + { TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, 40 }, + // TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + // TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + { TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, 5 } }; [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [MemberData(nameof(DecodeJpegData))] - public void DecodeJpeg(string fileName) + public void DecodeJpeg(string fileName, int executionCount) { - this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); + var decoder = new JpegDecoder() + { + IgnoreMetadata = true + }; + this.DecodeJpegBenchmarkImpl(fileName, decoder, executionCount); } - private void DecodeJpegBenchmarkImpl(string fileName, IImageDecoder decoder) + private void DecodeJpegBenchmarkImpl(string fileName, IImageDecoder decoder, int executionCount) { // do not run this on CI even by accident if (TestEnvironment.RunsOnCI) @@ -47,8 +54,6 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks return; } - const int ExecutionCount = 20; - if (!Vector.IsHardwareAccelerated) { throw new Exception("Vector.IsHardwareAccelerated == false! ('prefer32 bit' enabled?)"); @@ -58,7 +63,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks byte[] bytes = File.ReadAllBytes(path); this.Measure( - ExecutionCount, + executionCount, () => { var img = Image.Load(bytes, decoder); From 7c364dcd36ce743a061ce1514c33b52b319490d2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 29 Feb 2020 04:40:04 +0100 Subject: [PATCH 029/213] Tweak Block8x8F_CopyTo1x1 benchmarks --- .../BlockOperations/Block8x8F_CopyTo1x1.cs | 298 ++++++++++++++++-- 1 file changed, 276 insertions(+), 22 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs index 21d114be38..3f54d68c95 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -4,7 +4,9 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; - +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -13,13 +15,19 @@ using SixLabors.ImageSharp.Memory; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { - public class Block8x8F_CopyTo1x1 + public unsafe class Block8x8F_CopyTo1x1 { private Block8x8F block; + private readonly Block8x8F[] blockArray = new Block8x8F[1]; - private Buffer2D buffer; + private static readonly int Width = 100; - private BufferArea destArea; + private float[] buffer = new float[Width * 500]; + private readonly float[] unpinnedBuffer = new float[Width * 500]; + private GCHandle bufferHandle; + private GCHandle blockHandle; + private float* bufferPtr; + private float* blockPtr; [GlobalSetup] public void Setup() @@ -29,16 +37,30 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations throw new InvalidOperationException("Benchmark Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); } - this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); - this.destArea = this.buffer.GetArea(200, 100, 64, 64); + this.bufferHandle = GCHandle.Alloc(this.buffer, GCHandleType.Pinned); + this.bufferPtr = (float*)this.bufferHandle.AddrOfPinnedObject(); + + // Pin self so we can take address of to the block: + this.blockHandle = GCHandle.Alloc(this.blockArray, GCHandleType.Pinned); + this.blockPtr = (float*)Unsafe.AsPointer(ref this.block); + } + + [GlobalCleanup] + public void Cleanup() + { + this.bufferPtr = null; + this.blockPtr = null; + this.bufferHandle.Free(); + this.blockHandle.Free(); + this.buffer = null; } [Benchmark(Baseline = true)] public void Original() { ref byte selfBase = ref Unsafe.As(ref this.block); - ref byte destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); - int destStride = this.destArea.Stride * sizeof(float); + ref byte destBase = ref Unsafe.AsRef(this.bufferPtr); + int destStride = Width * sizeof(float); CopyRowImpl(ref selfBase, ref destBase, destStride, 0); CopyRowImpl(ref selfBase, ref destBase, destStride, 1); @@ -58,12 +80,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); } - [Benchmark] + // [Benchmark] public void UseVector8() { ref Block8x8F s = ref this.block; - ref float origin = ref this.destArea.GetReferenceToOrigin(); - int stride = this.destArea.Stride; + ref float origin = ref Unsafe.AsRef(this.bufferPtr); + int stride = Width; ref Vector d0 = ref Unsafe.As>(ref origin); ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride)); @@ -93,12 +115,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations d7 = row7; } - [Benchmark] + // [Benchmark] public void UseVector8_V2() { ref Block8x8F s = ref this.block; - ref float origin = ref this.destArea.GetReferenceToOrigin(); - int stride = this.destArea.Stride; + ref float origin = ref Unsafe.AsRef(this.bufferPtr); + int stride = Width; ref Vector d0 = ref Unsafe.As>(ref origin); ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride)); @@ -119,15 +141,247 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations d7 = Unsafe.As>(ref s.V7L); } - // RESULTS: + [Benchmark] + public void UseVector8_V3() + { + int stride = Width * sizeof(float); + ref float d = ref this.unpinnedBuffer[0]; + ref Vector s = ref Unsafe.As>(ref this.block); + + Vector v0 = s; + Vector v1 = Unsafe.AddByteOffset(ref s, (IntPtr)1); + Vector v2 = Unsafe.AddByteOffset(ref s, (IntPtr)2); + Vector v3 = Unsafe.AddByteOffset(ref s, (IntPtr)3); + + Unsafe.As>(ref d) = v0; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)stride)) = v1; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 2))) = v2; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 3))) = v3; + + v0 = Unsafe.AddByteOffset(ref s, (IntPtr)4); + v1 = Unsafe.AddByteOffset(ref s, (IntPtr)5); + v2 = Unsafe.AddByteOffset(ref s, (IntPtr)6); + v3 = Unsafe.AddByteOffset(ref s, (IntPtr)7); + + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 4))) = v0; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 5))) = v1; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 6))) = v2; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 7))) = v3; + } + +#if SUPPORTS_RUNTIME_INTRINSICS + [Benchmark] + public void UseVector256_Avx2_Variant1() + { + int stride = Width; + float* d = this.bufferPtr; + float* s = this.blockPtr; + Vector256 v; + + v = Avx.LoadVector256(s); + Avx.Store(d, v); + + v = Avx.LoadVector256(s + 8); + Avx.Store(d + stride, v); + + v = Avx.LoadVector256(s + (8 * 2)); + Avx.Store(d + (stride * 2), v); + + v = Avx.LoadVector256(s + (8 * 3)); + Avx.Store(d + (stride * 3), v); + + v = Avx.LoadVector256(s + (8 * 4)); + Avx.Store(d + (stride * 4), v); + + v = Avx.LoadVector256(s + (8 * 5)); + Avx.Store(d + (stride * 5), v); + + v = Avx.LoadVector256(s + (8 * 6)); + Avx.Store(d + (stride * 6), v); + + v = Avx.LoadVector256(s + (8 * 7)); + Avx.Store(d + (stride * 7), v); + } + + [Benchmark] + public void UseVector256_Avx2_Variant2() + { + int stride = Width; + float* d = this.bufferPtr; + float* s = this.blockPtr; + + Vector256 v0 = Avx.LoadVector256(s); + Vector256 v1 = Avx.LoadVector256(s + 8); + Vector256 v2 = Avx.LoadVector256(s + (8 * 2)); + Vector256 v3 = Avx.LoadVector256(s + (8 * 3)); + Vector256 v4 = Avx.LoadVector256(s + (8 * 4)); + Vector256 v5 = Avx.LoadVector256(s + (8 * 5)); + Vector256 v6 = Avx.LoadVector256(s + (8 * 6)); + Vector256 v7 = Avx.LoadVector256(s + (8 * 7)); + + Avx.Store(d, v0); + Avx.Store(d + stride, v1); + Avx.Store(d + (stride * 2), v2); + Avx.Store(d + (stride * 3), v3); + Avx.Store(d + (stride * 4), v4); + Avx.Store(d + (stride * 5), v5); + Avx.Store(d + (stride * 6), v6); + Avx.Store(d + (stride * 7), v7); + } + + [Benchmark] + public void UseVector256_Avx2_Variant3() + { + int stride = Width; + float* d = this.bufferPtr; + float* s = this.blockPtr; + + Vector256 v0 = Avx.LoadVector256(s); + Vector256 v1 = Avx.LoadVector256(s + 8); + Vector256 v2 = Avx.LoadVector256(s + (8 * 2)); + Vector256 v3 = Avx.LoadVector256(s + (8 * 3)); + Avx.Store(d, v0); + Avx.Store(d + stride, v1); + Avx.Store(d + (stride * 2), v2); + Avx.Store(d + (stride * 3), v3); + + v0 = Avx.LoadVector256(s + (8 * 4)); + v1 = Avx.LoadVector256(s + (8 * 5)); + v2 = Avx.LoadVector256(s + (8 * 6)); + v3 = Avx.LoadVector256(s + (8 * 7)); + Avx.Store(d + (stride * 4), v0); + Avx.Store(d + (stride * 5), v1); + Avx.Store(d + (stride * 6), v2); + Avx.Store(d + (stride * 7), v3); + } + + [Benchmark] + public void UseVector256_Avx2_Variant3_RefCast() + { + int stride = Width; + ref float d = ref this.unpinnedBuffer[0]; + ref Vector256 s = ref Unsafe.As>(ref this.block); + + Vector256 v0 = s; + Vector256 v1 = Unsafe.Add(ref s, 1); + Vector256 v2 = Unsafe.Add(ref s, 2); + Vector256 v3 = Unsafe.Add(ref s, 3); + + Unsafe.As>(ref d) = v0; + Unsafe.As>(ref Unsafe.Add(ref d, stride)) = v1; + Unsafe.As>(ref Unsafe.Add(ref d, stride * 2)) = v2; + Unsafe.As>(ref Unsafe.Add(ref d, stride * 3)) = v3; + + v0 = Unsafe.Add(ref s, 4); + v1 = Unsafe.Add(ref s, 5); + v2 = Unsafe.Add(ref s, 6); + v3 = Unsafe.Add(ref s, 7); + + Unsafe.As>(ref Unsafe.Add(ref d, stride * 4)) = v0; + Unsafe.As>(ref Unsafe.Add(ref d, stride * 5)) = v1; + Unsafe.As>(ref Unsafe.Add(ref d, stride * 6)) = v2; + Unsafe.As>(ref Unsafe.Add(ref d, stride * 7)) = v3; + } + + [Benchmark] + public void UseVector256_Avx2_Variant3_RefCast_Mod() + { + int stride = Width * sizeof(float); + ref float d = ref this.unpinnedBuffer[0]; + ref Vector256 s = ref Unsafe.As>(ref this.block); + + Vector256 v0 = s; + Vector256 v1 = Unsafe.AddByteOffset(ref s, (IntPtr)1); + Vector256 v2 = Unsafe.AddByteOffset(ref s, (IntPtr)2); + Vector256 v3 = Unsafe.AddByteOffset(ref s, (IntPtr)3); + + Unsafe.As>(ref d) = v0; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)stride)) = v1; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 2))) = v2; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 3))) = v3; + + v0 = Unsafe.AddByteOffset(ref s, (IntPtr)4); + v1 = Unsafe.AddByteOffset(ref s, (IntPtr)5); + v2 = Unsafe.AddByteOffset(ref s, (IntPtr)6); + v3 = Unsafe.AddByteOffset(ref s, (IntPtr)7); + + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 4))) = v0; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 5))) = v1; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 6))) = v2; + Unsafe.As>(ref Unsafe.AddByteOffset(ref d, (IntPtr)(stride * 7))) = v3; + } + + // [Benchmark] + public void UseVector256_Avx2_Variant3_WithLocalPinning() + { + int stride = Width; + fixed (float* d = this.unpinnedBuffer) + fixed (Block8x8F* ss = &this.block) + { + var s = (float*)ss; + Vector256 v0 = Avx.LoadVector256(s); + Vector256 v1 = Avx.LoadVector256(s + 8); + Vector256 v2 = Avx.LoadVector256(s + (8 * 2)); + Vector256 v3 = Avx.LoadVector256(s + (8 * 3)); + Avx.Store(d, v0); + Avx.Store(d + stride, v1); + Avx.Store(d + (stride * 2), v2); + Avx.Store(d + (stride * 3), v3); + + v0 = Avx.LoadVector256(s + (8 * 4)); + v1 = Avx.LoadVector256(s + (8 * 5)); + v2 = Avx.LoadVector256(s + (8 * 6)); + v3 = Avx.LoadVector256(s + (8 * 7)); + Avx.Store(d + (stride * 4), v0); + Avx.Store(d + (stride * 5), v1); + Avx.Store(d + (stride * 6), v2); + Avx.Store(d + (stride * 7), v3); + } + } + + // [Benchmark] + public void UseVector256_Avx2_Variant3_sbyte() + { + int stride = Width * 4; + var d = (sbyte*)this.bufferPtr; + var s = (sbyte*)this.blockPtr; + + Vector256 v0 = Avx.LoadVector256(s); + Vector256 v1 = Avx.LoadVector256(s + 32); + Vector256 v2 = Avx.LoadVector256(s + (32 * 2)); + Vector256 v3 = Avx.LoadVector256(s + (32 * 3)); + Avx.Store(d, v0); + Avx.Store(d + stride, v1); + Avx.Store(d + (stride * 2), v2); + Avx.Store(d + (stride * 3), v3); + + v0 = Avx.LoadVector256(s + (32 * 4)); + v1 = Avx.LoadVector256(s + (32 * 5)); + v2 = Avx.LoadVector256(s + (32 * 6)); + v3 = Avx.LoadVector256(s + (32 * 7)); + Avx.Store(d + (stride * 4), v0); + Avx.Store(d + (stride * 5), v1); + Avx.Store(d + (stride * 6), v2); + Avx.Store(d + (stride * 7), v3); + } +#endif + + // *** RESULTS 02/2020 *** + // BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18363 + // Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores + // .NET Core SDK=3.1.200-preview-014971 + // [Host] : .NET Core 3.1.2 (CoreCLR 4.700.20.6602, CoreFX 4.700.20.6702), X64 RyuJIT + // DefaultJob : .NET Core 3.1.2 (CoreCLR 4.700.20.6602, CoreFX 4.700.20.6702), X64 RyuJIT // - // Method | Mean | Error | StdDev | Scaled | - // -------------- |---------:|----------:|----------:|-------:| - // Original | 22.53 ns | 0.1660 ns | 0.1553 ns | 1.00 | - // UseVector8 | 21.59 ns | 0.3079 ns | 0.2571 ns | 0.96 | - // UseVector8_V2 | 22.57 ns | 0.1699 ns | 0.1506 ns | 1.00 | // - // Conclusion: - // Doesn't worth to bother with this + // | Method | Mean | Error | StdDev | Ratio | RatioSD | + // |--------------------------------------- |---------:|----------:|----------:|------:|--------:| + // | Original | 4.012 ns | 0.0567 ns | 0.0531 ns | 1.00 | 0.00 | + // | UseVector8_V3 | 4.013 ns | 0.0947 ns | 0.0840 ns | 1.00 | 0.03 | + // | UseVector256_Avx2_Variant1 | 2.546 ns | 0.0376 ns | 0.0314 ns | 0.63 | 0.01 | + // | UseVector256_Avx2_Variant2 | 2.643 ns | 0.0162 ns | 0.0151 ns | 0.66 | 0.01 | + // | UseVector256_Avx2_Variant3 | 2.520 ns | 0.0760 ns | 0.0813 ns | 0.63 | 0.02 | + // | UseVector256_Avx2_Variant3_RefCast | 2.300 ns | 0.0877 ns | 0.0938 ns | 0.58 | 0.03 | + // | UseVector256_Avx2_Variant3_RefCast_Mod | 2.139 ns | 0.0698 ns | 0.0686 ns | 0.53 | 0.02 | } } From d113c787fdf00c2b9e9a276b939b79c70733a6d1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 1 Mar 2020 00:35:56 +1100 Subject: [PATCH 030/213] Dump progress so far --- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoder.cs | 3 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 54 +++++++--------- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- .../Processors/Dithering/ErrorDither.cs | 2 +- .../Processors/Dithering/OrderedDither.cs | 6 +- .../Quantization/EuclideanPixelMap{TPixel}.cs | 33 +++++----- .../Quantization/FrameQuantizerExtensions.cs | 18 +++--- .../Quantization/IFrameQuantizer{TPixel}.cs | 6 +- .../OctreeFrameQuantizer{TPixel}.cs | 61 ++++++++++--------- .../PaletteFrameQuantizer{TPixel}.cs | 56 ++++++++++++++--- .../Quantization/PaletteQuantizer.cs | 16 ++--- .../Quantization/QuantizeProcessor{TPixel}.cs | 2 +- .../Quantization/QuantizedFrame{TPixel}.cs | 18 ++++-- .../Quantization/WuFrameQuantizer{TPixel}.cs | 56 ++++++----------- .../ImageSharp.Benchmarks/Codecs/EncodeGif.cs | 14 ++--- .../Quantization/QuantizedImageTests.cs | 2 +- .../Quantization/WuQuantizerTests.cs | 8 +-- 19 files changed, 186 insertions(+), 175 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 0d25210a99..ed5ed42933 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -339,7 +339,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp using IFrameQuantizer quantizer = this.quantizer.CreateFrameQuantizer(this.configuration); using QuantizedFrame quantized = quantizer.QuantizeFrame(image, image.Bounds()); - ReadOnlySpan quantizedColors = quantized.Palette.Span; + ReadOnlySpan quantizedColors = quantized.Palette; var color = default(Rgba32); // TODO: Use bulk conversion here for better perf diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index 978609d7fb..53c4c6f3fd 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -4,6 +4,7 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Formats.Gif @@ -17,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Gets or sets the quantizer for reducing the color count. /// Defaults to the /// - public IQuantizer Quantizer { get; set; } = new OctreeQuantizer(); + public IQuantizer Quantizer { get; set; } = KnownQuantizers.Octree; /// /// Gets or sets the color table mode: Global or local. diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index e32910d37b..87317a3ef5 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } // Clean up. - quantized?.Dispose(); + quantized.Dispose(); // TODO: Write extension etc stream.WriteByte(GifConstants.EndIntroducer); @@ -142,11 +142,9 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using (var paletteFrameQuantizer = new PaletteFrameQuantizer(this.configuration, this.quantizer.Options, quantized.Palette)) - using (QuantizedFrame paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds())) - { - this.WriteImageData(paletteQuantized, stream); - } + using var paletteFrameQuantizer = new PaletteFrameQuantizer(this.configuration, this.quantizer.Options, quantized.Palette); + using QuantizedFrame paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds()); + this.WriteImageData(paletteQuantized, stream); } } } @@ -156,8 +154,9 @@ namespace SixLabors.ImageSharp.Formats.Gif { ImageFrame previousFrame = null; GifFrameMetadata previousMeta = null; - foreach (ImageFrame frame in image.Frames) + for (int i = 0; i < image.Frames.Count; i++) { + ImageFrame frame = image.Frames[i]; ImageFrameMetadata metadata = frame.Metadata; GifFrameMetadata frameMetadata = metadata.GetGifMetadata(); if (quantized is null) @@ -173,17 +172,13 @@ namespace SixLabors.ImageSharp.Formats.Gif MaxColors = frameMetadata.ColorTableLength }; - using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration, options)) - { - quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); - } + using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration, options); + quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); } else { - using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration)) - { - quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); - } + using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration); + quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); } } @@ -193,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.WriteColorTable(quantized, stream); this.WriteImageData(quantized, stream); - quantized?.Dispose(); + quantized.Dispose(); quantized = null; // So next frame can regenerate it previousFrame = frame; previousMeta = frameMetadata; @@ -219,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette.Span, rgbaSpan); + PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { @@ -391,7 +386,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The extension to write to the stream. /// The stream to write to. - public void WriteExtension(IGifExtension extension, Stream stream) + private void WriteExtension(TGifExtension extension, Stream stream) + where TGifExtension : struct, IGifExtension { this.buffer[0] = GifConstants.ExtensionIntroducer; this.buffer[1] = extension.Label; @@ -444,15 +440,13 @@ namespace SixLabors.ImageSharp.Formats.Gif int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; int pixelCount = image.Palette.Length; - using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) - { - PixelOperations.Instance.ToRgb24Bytes( - this.configuration, - image.Palette.Span, - colorTable.GetSpan(), - pixelCount); - stream.Write(colorTable.Array, 0, colorTableLength); - } + using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength); + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + image.Palette, + colorTable.GetSpan(), + pixelCount); + stream.Write(colorTable.Array, 0, colorTableLength); } /// @@ -464,10 +458,8 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteImageData(QuantizedFrame image, Stream stream) where TPixel : unmanaged, IPixel { - using (var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth)) - { - encoder.Encode(image.GetPixelSpan(), stream); - } + using var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth); + encoder.Encode(image.GetPixelSpan(), stream); } } } diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index eda0c5fb8c..056076bf01 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -274,7 +274,7 @@ namespace SixLabors.ImageSharp.Formats.Gif ent = this.NextPixel(indexedPixels); - // TODO: PERF: It looks likt hshift could be calculated once statically. + // TODO: PERF: It looks like hshift could be calculated once statically. hshift = 0; for (fcode = this.hsize; fcode < 65536; fcode *= 2) { diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index ce624f768a..ed2fe143bb 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -555,7 +555,7 @@ namespace SixLabors.ImageSharp.Formats.Png } // Grab the palette and write it to the stream. - ReadOnlySpan palette = quantized.Palette.Span; + ReadOnlySpan palette = quantized.Palette; int paletteLength = Math.Min(palette.Length, 256); int colorTableLength = paletteLength * 3; bool anyAlpha = false; diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 3d18ef3587..9217d1c3f7 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering where TFrameQuantizer : struct, IFrameQuantizer where TPixel : unmanaged, IPixel { - ReadOnlySpan paletteSpan = destination.Palette.Span; + ReadOnlySpan paletteSpan = destination.Palette; int offsetY = bounds.Top; int offsetX = bounds.Left; float scale = quantizer.Options.DitherScale; diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 00ee4a7e63..c5b4135f56 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -203,7 +203,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering private readonly ImageFrame source; private readonly QuantizedFrame destination; private readonly Rectangle bounds; - private readonly ReadOnlyMemory palette; private readonly int bitDepth; [MethodImpl(InliningOptions.ShortMethod)] @@ -219,14 +218,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering this.source = source; this.destination = destination; this.bounds = bounds; - this.palette = destination.Palette; - this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(destination.Palette.Span.Length); + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(destination.Palette.Length); } [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { - ReadOnlySpan paletteSpan = this.palette.Span; + ReadOnlySpan paletteSpan = this.destination.Palette; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; float scale = this.quantizer.Options.DitherScale; diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 7a789164fd..615a7238b8 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// - /// Gets the closest color to the supplied color based upon the Eucladean distance. + /// Gets the closest color to the supplied color based upon the Euclidean distance. /// TODO: Expose this somehow. /// /// The pixel format. @@ -62,18 +62,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ReadOnlySpan paletteSpan = this.Palette.Span; // Check if the color is in the lookup table - if (this.distanceCache.TryGetValue(color, out int index)) + if (!this.distanceCache.TryGetValue(color, out int index)) { - match = paletteSpan[index]; - return index; + return this.GetClosestColorSlow(color, paletteSpan, out match); } - return this.GetClosestColorSlow(color, paletteSpan, out match); + match = paletteSpan[index]; + return index; } /// - public override int GetHashCode() - => this.vectorCache.GetHashCode(); + public override int GetHashCode() => this.vectorCache.GetHashCode(); [MethodImpl(InliningOptions.ShortMethod)] private int GetClosestColorSlow(TPixel color, ReadOnlySpan palette, out TPixel match) @@ -88,17 +87,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Vector4 candidate = this.vectorCache[i]; float distance = Vector4.DistanceSquared(vector, candidate); + if (!(distance < leastDistance)) + { + continue; + } + // Less than... assign. - if (distance < leastDistance) + index = i; + leastDistance = distance; + + // And if it's an exact match, exit the loop + if (distance == 0) { - index = i; - leastDistance = distance; - - // And if it's an exact match, exit the loop - if (distance == 0) - { - break; - } + break; } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs index a589f7524d..d6d8b98dae 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The type of frame quantizer. /// The pixel format. - /// The frame + /// The frame quantizer. /// The source image frame to quantize. /// The bounds within the frame to quantize. /// @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization var interest = Rectangle.Intersect(source.Bounds(), bounds); // Collect the palette. Required before the second pass runs. - ReadOnlyMemory palette = quantizer.BuildPalette(source, interest); + ReadOnlySpan palette = quantizer.BuildPalette(source, interest); MemoryAllocator memoryAllocator = quantizer.Configuration.MemoryAllocator; var quantizedFrame = new QuantizedFrame(memoryAllocator, interest.Width, interest.Height, palette); @@ -49,10 +49,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization else { // We clone the image as we don't want to alter the original via error diffusion based dithering. - using (ImageFrame clone = source.Clone()) - { - SecondPass(ref quantizer, clone, quantizedFrame, interest); - } + using ImageFrame clone = source.Clone(); + SecondPass(ref quantizer, clone, quantizedFrame, interest); } return quantizedFrame; @@ -71,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (dither is null) { - var operation = new RowIntervalOperation(quantizer, source, destination, bounds); + var operation = new RowIntervalOperation(ref quantizer, source, destination, bounds); ParallelRowIterator.IterateRows( quantizer.Configuration, bounds, @@ -91,11 +89,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private readonly ImageFrame source; private readonly QuantizedFrame destination; private readonly Rectangle bounds; - private readonly ReadOnlyMemory palette; [MethodImpl(InliningOptions.ShortMethod)] public RowIntervalOperation( - in TFrameQuantizer quantizer, + ref TFrameQuantizer quantizer, ImageFrame source, QuantizedFrame destination, Rectangle bounds) @@ -104,13 +101,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.source = source; this.destination = destination; this.bounds = bounds; - this.palette = destination.Palette; } [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { - ReadOnlySpan paletteSpan = this.palette.Span; + ReadOnlySpan paletteSpan = this.destination.Palette; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index 57e8fc3f35..506767277d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -38,8 +38,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The source image frame. /// The region of interest bounds. - /// The palette. - ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds); + /// The palette. + ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds); /// /// Returns the index and color from the quantized palette corresponding to the given color. @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The output color palette. /// The matched color. /// The index. - public byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match); + byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match); // TODO: Enable bulk operations. // void GetQuantizedColors(ReadOnlySpan colors, ReadOnlySpan palette, Span indices, Span matches); diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 1b7c9edd64..946ae399bb 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -3,7 +3,6 @@ using System; using System.Buffers; -using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; @@ -22,8 +21,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { private readonly int colors; private readonly Octree octree; + private IMemoryOwner palette; private EuclideanPixelMap pixelMap; private readonly bool isDithering; + private bool isDisposed; /// /// Initializes a new instance of the struct. @@ -41,8 +42,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.colors = this.Options.MaxColors; this.octree = new Octree(ImageMaths.GetBitsNeededForColorDepth(this.colors).Clamp(1, 8)); + this.palette = configuration.MemoryAllocator.Allocate(this.colors, AllocationOptions.Clean); this.pixelMap = default; this.isDithering = !(this.Options.Dither is null); + this.isDisposed = false; } /// @@ -53,12 +56,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerExtensions.QuantizeFrame(ref this, source, bounds); + public readonly QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) + public ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds) { using IMemoryOwner buffer = this.Configuration.MemoryAllocator.Allocate(bounds.Width); Span bufferSpan = buffer.GetSpan(); @@ -78,15 +81,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - TPixel[] palette = this.octree.Palletize(this.colors); - this.pixelMap = new EuclideanPixelMap(palette); + Span paletteSpan = this.palette.GetSpan(); + this.octree.Palletize(paletteSpan, this.colors); - return palette; + // TODO: Cannot make method readonly due to this line. + this.pixelMap = new EuclideanPixelMap(this.palette.Memory); + + return paletteSpan; } /// [MethodImpl(InliningOptions.ShortMethod)] - public byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) + public readonly byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) { // Octree only maps the RGB component of a color // so cannot tell the difference between a fully transparent @@ -104,6 +110,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public void Dispose() { + if (!this.isDisposed) + { + this.isDisposed = true; + this.palette.Dispose(); + this.palette = null; + } } /// @@ -116,14 +128,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// private static readonly byte[] Mask = new byte[] { - 0b10000000, - 0b1000000, - 0b100000, - 0b10000, - 0b1000, - 0b100, - 0b10, - 0b1 + 0b10000000, 0b1000000, 0b100000, 0b10000, 0b1000, 0b100, 0b10, 0b1 }; /// @@ -216,26 +221,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Convert the nodes in the Octree to a palette with a maximum of colorCount colors /// + /// The palette to fill. /// The maximum number of colors - /// - /// An with the palletized colors - /// [MethodImpl(InliningOptions.ShortMethod)] - public TPixel[] Palletize(int colorCount) + public void Palletize(Span palette, int colorCount) { while (this.Leaves > colorCount - 1) { this.Reduce(); } - // Now palletize the nodes - var palette = new TPixel[colorCount]; - int paletteIndex = 0; this.root.ConstructPalette(palette, ref paletteIndex); - - // And return the palette - return palette; } /// @@ -437,12 +434,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The palette /// The current palette index [MethodImpl(InliningOptions.ColdPath)] - public void ConstructPalette(TPixel[] palette, ref int index) + public void ConstructPalette(Span palette, ref int index) { if (this.leaf) { // Set the color of the palette entry - var vector = Vector3.Clamp(new Vector3(this.red, this.green, this.blue) / this.pixelCount, Vector3.Zero, new Vector3(255)); + var vector = Vector3.Clamp( + new Vector3(this.red, this.green, this.blue) / this.pixelCount, + Vector3.Zero, + new Vector3(255)); + TPixel pixel = default; pixel.FromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); palette[index] = pixel; @@ -516,8 +517,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization int shift = 7 - level; byte mask = Mask[level]; return ((color.R & mask) >> shift) - | ((color.G & mask) >> (shift - 1)) - | ((color.B & mask) >> (shift - 2)); + | ((color.G & mask) >> (shift - 1)) + | ((color.B & mask) >> (shift - 2)); } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index 3200dfab88..7960f728af 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Quantization @@ -15,8 +17,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization internal struct PaletteFrameQuantizer : IFrameQuantizer where TPixel : unmanaged, IPixel { - private readonly ReadOnlyMemory palette; + private IMemoryOwner paletteOwner; private readonly EuclideanPixelMap pixelMap; + private bool isDisposed; /// /// Initializes a new instance of the struct. @@ -25,7 +28,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The quantizer options defining quantization rules. /// A containing all colors in the palette. [MethodImpl(InliningOptions.ShortMethod)] - public PaletteFrameQuantizer(Configuration configuration, QuantizerOptions options, ReadOnlyMemory colors) + public PaletteFrameQuantizer(Configuration configuration, QuantizerOptions options, ReadOnlySpan colors) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(options, nameof(options)); @@ -33,8 +36,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.Configuration = configuration; this.Options = options; - this.palette = colors; - this.pixelMap = new EuclideanPixelMap(colors); + int maxLength = Math.Min(colors.Length, options.MaxColors); + this.paletteOwner = configuration.MemoryAllocator.Allocate(maxLength); + Color.ToPixel(configuration, colors, this.paletteOwner.GetSpan()); + + this.pixelMap = new EuclideanPixelMap(this.paletteOwner.Memory); + this.isDisposed = false; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The configuration which allows altering default behaviour or extending the library. + /// The quantizer options defining quantization rules. + /// A containing all colors in the palette. + [MethodImpl(InliningOptions.ShortMethod)] + public PaletteFrameQuantizer(Configuration configuration, QuantizerOptions options, ReadOnlySpan palette) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(options, nameof(options)); + + this.Configuration = configuration; + this.Options = options; + + int maxLength = Math.Min(palette.Length, options.MaxColors); + this.paletteOwner = configuration.MemoryAllocator.Allocate(maxLength); + palette.CopyTo(this.paletteOwner.GetSpan()); + + this.pixelMap = new EuclideanPixelMap(this.paletteOwner.Memory); + this.isDisposed = false; } /// @@ -45,22 +75,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerExtensions.QuantizeFrame(ref this, source, bounds); + public readonly QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) - => this.palette; + public readonly ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds) + => this.paletteOwner.GetSpan(); /// [MethodImpl(InliningOptions.ShortMethod)] - public byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) + public readonly byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) => (byte)this.pixelMap.GetClosestColor(color, out match); /// public void Dispose() { + if (this.isDisposed) + { + return; + } + + this.isDisposed = true; + this.paletteOwner.Dispose(); + this.paletteOwner = null; } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 07fa6e41e5..75a0f39389 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -11,6 +11,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class PaletteQuantizer : IQuantizer { + private readonly ReadOnlyMemory palette; + /// /// Initializes a new instance of the class. /// @@ -30,15 +32,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.MustBeGreaterThan(palette.Length, 0, nameof(palette)); Guard.NotNull(options, nameof(options)); - this.Palette = palette; + this.palette = palette; this.Options = options; } - /// - /// Gets the color palette. - /// - public ReadOnlyMemory Palette { get; } - /// public QuantizerOptions Options { get; } @@ -52,12 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization where TPixel : unmanaged, IPixel { Guard.NotNull(options, nameof(options)); - - int length = Math.Min(this.Palette.Span.Length, options.MaxColors); - var palette = new TPixel[length]; - - Color.ToPixel(configuration, this.Palette.Span, palette.AsSpan()); - return new PaletteFrameQuantizer(configuration, options, palette); + return new PaletteFrameQuantizer(configuration, options, this.palette.Span); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index 5a0116a03f..04586807e7 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public void Invoke(in RowInterval rows) { ReadOnlySpan quantizedPixelSpan = this.quantized.GetPixelSpan(); - ReadOnlySpan paletteSpan = this.quantized.Palette.Span; + ReadOnlySpan paletteSpan = this.quantized.Palette; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; int width = this.bounds.Width; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index 07e89a2b0c..cda0546e4a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -16,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public sealed class QuantizedFrame : IDisposable where TPixel : unmanaged, IPixel { + private IMemoryOwner palette; private IMemoryOwner pixels; private bool isDisposed; @@ -26,15 +27,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The image width. /// The image height. /// The color palette. - internal QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, ReadOnlyMemory palette) + internal QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, ReadOnlySpan palette) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); this.Width = width; this.Height = height; - this.Palette = palette; this.pixels = memoryAllocator.AllocateManagedByteBuffer(width * height, AllocationOptions.Clean); + + this.palette = memoryAllocator.Allocate(palette.Length); + palette.CopyTo(this.palette.GetSpan()); } /// @@ -50,7 +53,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Gets the color palette of this . /// - public ReadOnlyMemory Palette { get; private set; } + public ReadOnlySpan Palette + { + [MethodImpl(InliningOptions.ShortMethod)] + get { return this.palette.GetSpan(); } + } /// /// Gets the pixels of this . @@ -72,15 +79,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public void Dispose() { - if (this.isDisposed) + if (!this.isDisposed) { return; } this.isDisposed = true; this.pixels?.Dispose(); + this.palette?.Dispose(); this.pixels = null; - this.Palette = null; + this.palette = null; } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 177f7e8590..5054772582 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -65,30 +65,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// private const int TableLength = IndexCount * IndexCount * IndexCount * IndexAlphaCount; - /// - /// Color moments. - /// private IMemoryOwner moments; - - /// - /// Color space tag. - /// private IMemoryOwner tag; - - /// - /// Maximum allowed color depth - /// + private IMemoryOwner palette; private int colors; - - /// - /// The color cube representing the image palette - /// private readonly Box[] colorCube; - private EuclideanPixelMap pixelMap; - private readonly bool isDithering; - private bool isDisposed; /// @@ -104,10 +87,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.Configuration = configuration; this.Options = options; + this.colors = this.Options.MaxColors; this.memoryAllocator = this.Configuration.MemoryAllocator; this.moments = this.memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); this.tag = this.memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.colors = this.Options.MaxColors; + this.palette = this.memoryAllocator.Allocate(this.colors, AllocationOptions.Clean); this.colorCube = new Box[this.colors]; this.isDisposed = false; this.pixelMap = default; @@ -122,19 +106,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerExtensions.QuantizeFrame(ref this, source, bounds); + public readonly QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// - public ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) + public ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds) { this.Build3DHistogram(source, bounds); this.Get3DMoments(this.memoryAllocator); this.BuildCube(); - var palette = new TPixel[this.colors]; ReadOnlySpan momentsSpan = this.moments.GetSpan(); - + Span paletteSpan = this.palette.GetSpan(); for (int k = 0; k < this.colors; k++) { this.Mark(ref this.colorCube[k], (byte)k); @@ -143,17 +126,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (moment.Weight > 0) { - ref TPixel color = ref palette[k]; + ref TPixel color = ref paletteSpan[k]; color.FromScaledVector4(moment.Normalize()); } } - this.pixelMap = new EuclideanPixelMap(palette); - return palette; + // TODO: Cannot make methods readonly due to this line. + this.pixelMap = new EuclideanPixelMap(this.palette.Memory); + return paletteSpan; } /// - public byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) + public readonly byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) { if (!this.isDithering) { @@ -177,16 +161,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public void Dispose() { - if (this.isDisposed) + if (!this.isDisposed) { - return; + this.isDisposed = true; + this.moments?.Dispose(); + this.tag?.Dispose(); + this.palette?.Dispose(); + this.moments = null; + this.tag = null; + this.palette = null; } - - this.isDisposed = true; - this.moments?.Dispose(); - this.tag?.Dispose(); - this.moments = null; - this.tag = null; } /// diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs index 5e91f98eb1..71405890cd 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs @@ -21,6 +21,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs private SDImage bmpDrawing; private Image bmpCore; + // Try to get as close to System.Drawing's output as possible + private readonly GifEncoder encoder = new GifEncoder + { + Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 }) + }; + [GlobalSetup] public void ReadImages() { @@ -53,15 +59,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs [Benchmark(Description = "ImageSharp Gif")] public void GifCore() { - // Try to get as close to System.Drawing's output as possible - var options = new GifEncoder - { - Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 }) - }; - using (var memoryStream = new MemoryStream()) { - this.bmpCore.SaveAsGif(memoryStream, options); + this.bmpCore.SaveAsGif(memoryStream, this.encoder); } } } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index cd93ab0cf8..4085d99439 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests // Transparent pixels are much more likely to be found at the end of a palette int index = -1; Rgba32 trans = default; - ReadOnlySpan paletteSpan = quantized.Palette.Span; + ReadOnlySpan paletteSpan = quantized.Palette; for (int i = paletteSpan.Length - 1; i >= 0; i--) { paletteSpan[i].ToRgba32(ref trans); diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index f3bcd0b955..34888f1dbc 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); - Assert.Equal(Color.Black, (Color)result.Palette.Span[0]); + Assert.Equal(Color.Black, (Color)result.Palette[0]); Assert.Equal(0, result.GetPixelSpan()[0]); } @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); - Assert.Equal(default, result.Palette.Span[0]); + Assert.Equal(default, result.Palette[0]); Assert.Equal(0, result.GetPixelSpan()[0]); } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization var actualImage = new Image(1, 256); - ReadOnlySpan paletteSpan = result.Palette.Span; + ReadOnlySpan paletteSpan = result.Palette; int paletteCount = result.Palette.Length - 1; for (int y = 0; y < actualImage.Height; y++) { @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(4 * 8, result.Palette.Length); Assert.Equal(256, result.GetPixelSpan().Length); - ReadOnlySpan paletteSpan = result.Palette.Span; + ReadOnlySpan paletteSpan = result.Palette; int paletteCount = result.Palette.Length - 1; for (int y = 0; y < actualImage.Height; y++) { From 48d3963cddcf8d804e55fb57866227f737fa1f41 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 29 Feb 2020 16:52:36 +0100 Subject: [PATCH 031/213] cold/hot path microoptimizations based on Resize profile --- .../ArrayPoolMemoryAllocator.Buffer{T}.cs | 9 +++- .../Allocators/ArrayPoolMemoryAllocator.cs | 8 +++- src/ImageSharp/Memory/Buffer2DExtensions.cs | 46 ------------------- src/ImageSharp/Memory/Buffer2D{T}.cs | 46 +++++++++++++++++++ .../Transforms/Resize/ResizeKernelMap.cs | 18 +++++--- 5 files changed, 72 insertions(+), 55 deletions(-) diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs index 7a8b4f8bd7..131abc5d21 100644 --- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory.Internals; @@ -50,7 +51,7 @@ namespace SixLabors.ImageSharp.Memory { if (this.Data == null) { - throw new ObjectDisposedException("ArrayPoolMemoryAllocator.Buffer"); + ThrowObjectDisposedException(); } return MemoryMarshal.Cast(this.Data.AsSpan()).Slice(0, this.length); @@ -74,6 +75,12 @@ namespace SixLabors.ImageSharp.Memory } protected override object GetPinnableObject() => this.Data; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowObjectDisposedException() + { + throw new ObjectDisposedException("ArrayPoolMemoryAllocator.Buffer"); + } } /// diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs index 8043c18881..4a04cb5d6e 100644 --- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs @@ -133,8 +133,7 @@ namespace SixLabors.ImageSharp.Memory int bufferSizeInBytes = length * itemSizeBytes; if (bufferSizeInBytes < 0 || bufferSizeInBytes > this.BufferCapacityInBytes) { - throw new InvalidMemoryOperationException( - $"Requested allocation: {length} elements of {typeof(T).Name} is over the capacity of the MemoryAllocator."); + ThrowInvalidAllocationException(length); } ArrayPool pool = this.GetArrayPool(bufferSizeInBytes); @@ -171,6 +170,11 @@ namespace SixLabors.ImageSharp.Memory return maxPoolSizeInBytes / 4; } + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowInvalidAllocationException(int length) => + throw new InvalidMemoryOperationException( + $"Requested allocation: {length} elements of {typeof(T).Name} is over the capacity of the MemoryAllocator."); + private ArrayPool GetArrayPool(int bufferSizeInBytes) { return bufferSizeInBytes <= this.PoolSelectorThresholdInBytes ? this.normalArrayPool : this.largeArrayPool; diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index 8b0f3845e0..fea44f52c1 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -27,52 +27,6 @@ namespace SixLabors.ImageSharp.Memory return buffer.FastMemoryGroup.View; } - /// - /// Gets a to the backing data of - /// if the backing group consists of one single contiguous memory buffer. - /// Throws otherwise. - /// - /// The . - /// The value type. - /// The referencing the memory area. - /// - /// Thrown when the backing group is discontiguous. - /// - internal static Span GetSingleSpan(this Buffer2D buffer) - where T : struct - { - Guard.NotNull(buffer, nameof(buffer)); - if (buffer.FastMemoryGroup.Count > 1) - { - throw new InvalidOperationException("GetSingleSpan is only valid for a single-buffer group!"); - } - - return buffer.FastMemoryGroup.Single().Span; - } - - /// - /// Gets a to the backing data of - /// if the backing group consists of one single contiguous memory buffer. - /// Throws otherwise. - /// - /// The . - /// The value type. - /// The . - /// - /// Thrown when the backing group is discontiguous. - /// - internal static Memory GetSingleMemory(this Buffer2D buffer) - where T : struct - { - Guard.NotNull(buffer, nameof(buffer)); - if (buffer.FastMemoryGroup.Count > 1) - { - throw new InvalidOperationException("GetSingleMemory is only valid for a single-buffer group!"); - } - - return buffer.FastMemoryGroup.Single(); - } - /// /// TODO: Does not work with multi-buffer groups, should be specific to Resize. /// Copy columns of inplace, diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index f22b9a8755..16b3b90630 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -158,6 +159,36 @@ namespace SixLabors.ImageSharp.Memory return this.FastMemoryGroup.View.GetBoundedSlice(y * this.Width, this.Width); } + /// + /// Gets a to the backing data if the backing group consists of a single contiguous memory buffer. + /// Throws otherwise. + /// + /// The referencing the memory area. + /// + /// Thrown when the backing group is discontiguous. + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal Span GetSingleSpan() + { + // TODO: If we need a public version of this method, we need to cache the non-fast Memory of this.MemoryGroup + return this.cachedMemory.Length != 0 ? this.cachedMemory.Span : ThrowInvalidOperationSingleSpan(); + } + + /// + /// Gets a to the backing data of if the backing group consists of a single contiguous memory buffer. + /// Throws otherwise. + /// + /// The . + /// + /// Thrown when the backing group is discontiguous. + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal Memory GetSingleMemory() + { + // TODO: If we need a public version of this method, we need to cache the non-fast Memory of this.MemoryGroup + return this.cachedMemory.Length != 0 ? this.cachedMemory : ThrowInvalidOperationSingleMemory(); + } + /// /// Swaps the contents of 'destination' with 'source' if the buffers are owned (1), /// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2! @@ -171,6 +202,9 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(InliningOptions.ColdPath)] private Memory GetRowMemorySlow(int y) => this.FastMemoryGroup.GetBoundedSlice(y * this.Width, this.Width); + [MethodImpl(InliningOptions.ColdPath)] + private Memory GetSingleMemorySlow() => this.FastMemoryGroup.Single(); + [MethodImpl(InliningOptions.ColdPath)] private ref T GetElementSlow(int x, int y) { @@ -196,5 +230,17 @@ namespace SixLabors.ImageSharp.Memory b.cachedMemory = aCached; } } + + [MethodImpl(InliningOptions.ColdPath)] + private static Memory ThrowInvalidOperationSingleMemory() + { + throw new InvalidOperationException("GetSingleMemory is only valid for a single-buffer group!"); + } + + [MethodImpl(InliningOptions.ColdPath)] + private static Span ThrowInvalidOperationSingleSpan() + { + throw new InvalidOperationException("GetSingleSpan is only valid for a single-buffer group!"); + } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 3e7ccbd0af..5390cbbd18 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; @@ -249,12 +250,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private unsafe ResizeKernel CreateKernel(int dataRowIndex, int left, int right) { int length = right - left + 1; - - if (length > this.data.Width) - { - throw new InvalidOperationException( - $"Error in KernelMap.CreateKernel({dataRowIndex},{left},{right}): left > this.data.Width"); - } + this.ValidateSizesForCreateKernel(length, dataRowIndex, left, right); Span rowSpan = this.data.GetRowSpan(dataRowIndex); @@ -262,5 +258,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); return new ResizeKernel(left, rowPtr, length); } + + [Conditional("DEBUG")] + private void ValidateSizesForCreateKernel(int length, int dataRowIndex, int left, int right) + { + if (length > this.data.Width) + { + throw new InvalidOperationException( + $"Error in KernelMap.CreateKernel({dataRowIndex},{left},{right}): left > this.data.Width"); + } + } } } From 1f2894af801be0dcfb1cb42216db599574155cea Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 29 Feb 2020 17:17:20 +0100 Subject: [PATCH 032/213] BufferArea optimizations --- src/ImageSharp/Memory/BufferArea{T}.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Memory/BufferArea{T}.cs b/src/ImageSharp/Memory/BufferArea{T}.cs index f5cbc69530..076f7f37ce 100644 --- a/src/ImageSharp/Memory/BufferArea{T}.cs +++ b/src/ImageSharp/Memory/BufferArea{T}.cs @@ -79,8 +79,12 @@ namespace SixLabors.ImageSharp.Memory /// /// The reference to the [0,0] element [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T GetReferenceToOrigin() => - ref this.GetRowSpan(0)[0]; + public ref T GetReferenceToOrigin() + { + int y = this.Rectangle.Y; + int x = this.Rectangle.X; + return ref this.DestinationBuffer.GetRowSpan(y)[x]; + } /// /// Gets a span to row 'y' inside this area. @@ -90,11 +94,11 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] public Span GetRowSpan(int y) { - int yy = this.GetRowIndex(y); + int yy = this.Rectangle.Y + y; int xx = this.Rectangle.X; int width = this.Rectangle.Width; - return this.DestinationBuffer.FastMemoryGroup.GetBoundedSlice(yy + xx, width).Span; + return this.DestinationBuffer.GetRowSpan(yy).Slice(xx, width); } /// @@ -129,12 +133,6 @@ namespace SixLabors.ImageSharp.Memory return new BufferArea(this.DestinationBuffer, rectangle); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal int GetRowIndex(int y) - { - return (y + this.Rectangle.Y) * this.DestinationBuffer.Width; - } - public void Clear() { // Optimization for when the size of the area is the same as the buffer size. From 7b7e50244d592879a186fb835ae05240f002204a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 29 Feb 2020 18:09:41 +0100 Subject: [PATCH 033/213] block scaling bottleneck -> eliminated --- .../Jpeg/Components/Block8x8F.CopyTo.cs | 33 +++++++++++-------- .../Decoder/JpegBlockPostProcessor.cs | 14 +++++--- .../Decoder/JpegComponentPostProcessor.cs | 16 ++++----- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 2 +- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index 64d1d68b7c..b7301f3e9c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -16,28 +16,35 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// [MethodImpl(InliningOptions.ShortMethod)] public void CopyTo(in BufferArea area, int horizontalScale, int verticalScale) + { + ref float areaOrigin = ref area.GetReferenceToOrigin(); + this.CopyTo(ref areaOrigin, area.Stride, horizontalScale, verticalScale); + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void CopyTo(ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale) { if (horizontalScale == 1 && verticalScale == 1) { - this.Copy1x1Scale(area); + this.Copy1x1Scale(ref areaOrigin, areaStride); return; } if (horizontalScale == 2 && verticalScale == 2) { - this.Copy2x2Scale(area); + this.Copy2x2Scale(ref areaOrigin, areaStride); return; } // TODO: Optimize: implement all cases with scale-specific, loopless code! - this.CopyArbitraryScale(area, horizontalScale, verticalScale); + this.CopyArbitraryScale(ref areaOrigin, areaStride, horizontalScale, verticalScale); } - public void Copy1x1Scale(in BufferArea destination) + public void Copy1x1Scale(ref float areaOrigin, int areaStride) { ref byte selfBase = ref Unsafe.As(ref this); - ref byte destBase = ref Unsafe.As(ref destination.GetReferenceToOrigin()); - int destStride = destination.Stride * sizeof(float); + ref byte destBase = ref Unsafe.As(ref areaOrigin); + int destStride = areaStride * sizeof(float); CopyRowImpl(ref selfBase, ref destBase, destStride, 0); CopyRowImpl(ref selfBase, ref destBase, destStride, 1); @@ -57,10 +64,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); } - private void Copy2x2Scale(in BufferArea area) + private void Copy2x2Scale(ref float areaOrigin, int areaStride) { - ref Vector2 destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); - int destStride = area.Stride / 2; + ref Vector2 destBase = ref Unsafe.As(ref areaOrigin); + int destStride = areaStride / 2; this.WidenCopyRowImpl2x2(ref destBase, 0, destStride); this.WidenCopyRowImpl2x2(ref destBase, 1, destStride); @@ -110,10 +117,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } [MethodImpl(InliningOptions.ColdPath)] - private void CopyArbitraryScale(BufferArea area, int horizontalScale, int verticalScale) + private void CopyArbitraryScale(ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale) { - ref float destBase = ref area.GetReferenceToOrigin(); - for (int y = 0; y < 8; y++) { int yy = y * verticalScale; @@ -127,12 +132,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components for (int i = 0; i < verticalScale; i++) { - int baseIdx = ((yy + i) * area.Stride) + xx; + int baseIdx = ((yy + i) * areaStride) + xx; for (int j = 0; j < horizontalScale; j++) { // area[xx + j, yy + i] = value; - Unsafe.Add(ref destBase, baseIdx + j) = value; + Unsafe.Add(ref areaOrigin, baseIdx + j) = value; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs index 44f9048a59..8c797463ba 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs @@ -68,11 +68,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// - Copy the resulting color values into 'destArea' scaling up the block by amount defined in . /// /// The source block. - /// The destination buffer area. + /// Reference to the origin of the destination pixel area. + /// The width of the destination pixel buffer. /// The maximum value derived from the bitdepth. public void ProcessBlockColorsInto( ref Block8x8 sourceBlock, - in BufferArea destArea, + ref float destAreaOrigin, + int destAreaStride, float maximumValue) { ref Block8x8F b = ref this.SourceBlock; @@ -88,7 +90,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // To be "more accurate", we need to emulate this by rounding! this.WorkspaceBlock1.NormalizeColorsAndRoundInplace(maximumValue); - this.WorkspaceBlock1.CopyTo(destArea, this.subSamplingDivisors.Width, this.subSamplingDivisors.Height); + this.WorkspaceBlock1.CopyTo( + ref destAreaOrigin, + destAreaStride, + this.subSamplingDivisors.Width, + this.subSamplingDivisors.Height); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index 22bc8ccaaa..b91287fb3d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -79,6 +79,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder var blockPp = new JpegBlockPostProcessor(this.ImagePostProcessor.RawJpeg, this.Component); float maximumValue = MathF.Pow(2, this.ImagePostProcessor.RawJpeg.Precision) - 1; + int destAreaStride = this.ColorBuffer.Width; + for (int y = 0; y < this.BlockRowsPerStep; y++) { int yBlock = this.currentComponentRowInBlocks + y; @@ -90,22 +92,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int yBuffer = y * this.blockAreaSize.Height; + Span colorBufferRow = this.ColorBuffer.GetRowSpan(yBuffer); Span blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock); - ref Block8x8 blockRowBase = ref MemoryMarshal.GetReference(blockRow); - for (int xBlock = 0; xBlock < this.SizeInBlocks.Width; xBlock++) { - ref Block8x8 block = ref Unsafe.Add(ref blockRowBase, xBlock); + ref Block8x8 block = ref blockRow[xBlock]; int xBuffer = xBlock * this.blockAreaSize.Width; + ref float destAreaOrigin = ref colorBufferRow[xBuffer]; - BufferArea destArea = this.ColorBuffer.GetArea( - xBuffer, - yBuffer, - this.blockAreaSize.Width, - this.blockAreaSize.Height); - - blockPp.ProcessBlockColorsInto(ref block, destArea, maximumValue); + blockPp.ProcessBlockColorsInto(ref block, ref destAreaOrigin, destAreaStride, maximumValue); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index ea2fc7ab80..e8af799320 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20, AllocationOptions.Clean)) { BufferArea area = buffer.GetArea(5, 10, 8, 8); - block.Copy1x1Scale(area); + block.Copy1x1Scale(ref area.GetReferenceToOrigin(), area.Stride); Assert.Equal(block[0, 0], buffer[5, 10]); Assert.Equal(block[1, 0], buffer[6, 10]); From cc056a695bca881097aa2daf9322482c25158edd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 29 Feb 2020 18:13:23 +0100 Subject: [PATCH 034/213] IsAvx2CompatibleArchitecture => HasVector8 --- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 8 ++++---- src/ImageSharp/Common/Helpers/SimdUtils.cs | 9 +++++---- src/ImageSharp/Common/Tuples/Vector4Pair.cs | 6 +++--- .../Jpeg/Components/Block8x8F.Generated.cs | 2 +- .../Jpeg/Components/Block8x8F.Generated.tt | 2 +- .../Formats/Jpeg/Components/Block8x8F.cs | 8 ++++---- .../JpegColorConverter.FromYCbCrSimd.cs | 16 ++++++++-------- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 2 +- .../Utils/Vector4Converters.RgbaCompatible.cs | 2 +- .../Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs | 2 +- tests/ImageSharp.Tests/Common/SimdUtilsTests.cs | 2 +- .../Formats/Jpg/Block8x8FTests.cs | 4 ++-- .../Formats/Jpg/JpegColorConverterTests.cs | 2 +- .../JpegProfilingBenchmarks.cs | 6 +++--- .../ResizeProfilingBenchmarks.cs | 2 +- 15 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index 690bf83095..ba3d9c4e83 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp /// public static class BasicIntrinsics256 { - public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture; + public static bool IsAvailable { get; } = HasVector8; #if !SUPPORTS_EXTENDED_INTRINSICS /// @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - VerifyIsAvx2Compatible(nameof(BulkConvertByteToNormalizedFloat)); + VerifyHasVector8(nameof(BulkConvertByteToNormalizedFloat)); VerifySpanInput(source, dest, 8); var bVec = new Vector(256.0f / 255.0f); @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) { - VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); + VerifyHasVector8(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); VerifySpanInput(source, dest, 8); if (source.Length == 0) @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp /// internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) { - VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByte)); + VerifyHasVector8(nameof(BulkConvertNormalizedFloatToByte)); VerifySpanInput(source, dest, 8); if (source.Length == 0) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 4c34e28bc8..08c256f842 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -15,9 +15,10 @@ namespace SixLabors.ImageSharp internal static partial class SimdUtils { /// - /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. + /// Gets a value indicating whether code is being JIT-ed to AVX2 instructions + /// where both float and integer registers are of size 256 byte. /// - public static bool IsAvx2CompatibleArchitecture { get; } = + public static bool HasVector8 { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; /// @@ -151,9 +152,9 @@ namespace SixLabors.ImageSharp private static byte ConvertToByte(float f) => (byte)ComparableExtensions.Clamp((f * 255f) + 0.5f, 0, 255f); [Conditional("DEBUG")] - private static void VerifyIsAvx2Compatible(string operation) + private static void VerifyHasVector8(string operation) { - if (!IsAvx2CompatibleArchitecture) + if (!HasVector8) { throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); } diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index b3a32deeef..1fdae0d5dd 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tuples /// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4! /// TODO: Move it somewhere else. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void RoundAndDownscalePreAvx2(float downscaleFactor) + internal void RoundAndDownscalePreVector8(float downscaleFactor) { ref Vector a = ref Unsafe.As>(ref this.A); a = a.FastRound(); @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Tuples /// TODO: Move it somewhere else. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void RoundAndDownscaleAvx2(float downscaleFactor) + internal void RoundAndDownscaleVector8(float downscaleFactor) { ref Vector self = ref Unsafe.As>(ref this); Vector v = self; @@ -79,4 +79,4 @@ namespace SixLabors.ImageSharp.Tuples return $"{nameof(Vector4Pair)}({this.A}, {this.B})"; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index 23b51f0926..033eedb924 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// AVX2-only variant for executing and in one step. /// [MethodImpl(InliningOptions.ShortMethod)] - public void NormalizeColorsAndRoundInplaceAvx2(float maximum) + public void NormalizeColorsAndRoundInplaceVector8(float maximum) { var off = new Vector(MathF.Ceiling(maximum / 2)); var max = new Vector(maximum); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index 176591972a..5370f27048 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// AVX2-only variant for executing and in one step. /// [MethodImpl(InliningOptions.ShortMethod)] - public void NormalizeColorsAndRoundInplaceAvx2(float maximum) + public void NormalizeColorsAndRoundInplaceVector8(float maximum) { var off = new Vector(MathF.Ceiling(maximum / 2)); var max = new Vector(maximum); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index f11b0f8fa7..f2a81e5c83 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -471,9 +471,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// public void NormalizeColorsAndRoundInplace(float maximum) { - if (SimdUtils.IsAvx2CompatibleArchitecture) + if (SimdUtils.HasVector8) { - this.NormalizeColorsAndRoundInplaceAvx2(maximum); + this.NormalizeColorsAndRoundInplaceVector8(maximum); } else { @@ -497,7 +497,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components public void LoadFrom(ref Block8x8 source) { #if SUPPORTS_EXTENDED_INTRINSICS - if (SimdUtils.IsAvx2CompatibleArchitecture) + if (SimdUtils.HasVector8) { this.LoadFromInt16ExtendedAvx2(ref source); return; @@ -513,7 +513,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components public void LoadFromInt16ExtendedAvx2(ref Block8x8 source) { DebugGuard.IsTrue( - SimdUtils.IsAvx2CompatibleArchitecture, + SimdUtils.HasVector8, "LoadFromUInt16ExtendedAvx2 only works on AVX2 compatible architecture!"); ref Vector sRef = ref Unsafe.As>(ref source); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 1706b4c1bc..09d6a4d1d8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -90,15 +90,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters if (Vector.Count == 4) { // TODO: Find a way to properly run & test this path on AVX2 PC-s! (Have I already mentioned that Vector is terrible?) - r.RoundAndDownscalePreAvx2(maxValue); - g.RoundAndDownscalePreAvx2(maxValue); - b.RoundAndDownscalePreAvx2(maxValue); + r.RoundAndDownscalePreVector8(maxValue); + g.RoundAndDownscalePreVector8(maxValue); + b.RoundAndDownscalePreVector8(maxValue); } - else if (SimdUtils.IsAvx2CompatibleArchitecture) + else if (SimdUtils.HasVector8) { - r.RoundAndDownscaleAvx2(maxValue); - g.RoundAndDownscaleAvx2(maxValue); - b.RoundAndDownscaleAvx2(maxValue); + r.RoundAndDownscaleVector8(maxValue); + g.RoundAndDownscaleVector8(maxValue); + b.RoundAndDownscaleVector8(maxValue); } else { @@ -114,4 +114,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index 093ea2f9a2..1165db2802 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public static bool IsAvailable => Vector.IsHardwareAccelerated && SimdUtils.IsAvx2CompatibleArchitecture; + public static bool IsAvailable => Vector.IsHardwareAccelerated && SimdUtils.HasVector8; public override void ConvertToRgba(in ComponentValues values, Span result) { diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index 11a23b6eb2..af04a06b7b 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils return int.MaxValue; } - return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; + return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.HasVector8 ? 256 : 128; } } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs index 3f54d68c95..b97ca14f38 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations [GlobalSetup] public void Setup() { - if (!SimdUtils.IsAvx2CompatibleArchitecture) + if (!SimdUtils.HasVector8) { throw new InvalidOperationException("Benchmark Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); } diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 6bf3d07457..cc5519c795 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Tests.Common private bool SkipOnNonAvx2([CallerMemberName] string testCaseName = null) { - if (!SimdUtils.IsAvx2CompatibleArchitecture) + if (!SimdUtils.HasVector8) { this.Output.WriteLine("Skipping AVX2 specific test case: " + testCaseName); return true; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index ef8804242f..2af8dfe797 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg private bool SkipOnNonAvx2Runner() { - if (!SimdUtils.IsAvx2CompatibleArchitecture) + if (!SimdUtils.HasVector8) { this.Output.WriteLine("AVX2 not supported, skipping!"); return true; @@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg expected.RoundInplace(); Block8x8F actual = source; - actual.NormalizeColorsAndRoundInplaceAvx2(255); + actual.NormalizeColorsAndRoundInplaceVector8(255); this.Output.WriteLine(expected.ToString()); this.Output.WriteLine(actual.ToString()); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 8775714257..7f0033cc5c 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [MemberData(nameof(CommonConversionData))] public void FromYCbCrSimdAvx2(int inputBufferLength, int resultBufferLength, int seed) { - if (!SimdUtils.IsAvx2CompatibleArchitecture) + if (!SimdUtils.HasVector8) { this.Output.WriteLine("No AVX2 present, skipping test!"); return; diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index 987de29ea9..358a5d0a01 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -30,12 +30,12 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, 20 }, { TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, 20 }, { TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, 40 }, - // TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, - // TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + // { TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, 10 }, + // { TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, 5 }, { TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, 5 } }; - [Theory(Skip = ProfilingSetup.SkipProfilingTests)] + [Theory] [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName, int executionCount) { diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs index ba5eb532b2..9b8a3d5a35 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks public int ExecutionCount { get; set; } = 50; - [Theory(Skip = ProfilingSetup.SkipProfilingTests)] + [Theory] [InlineData(100, 100)] [InlineData(2000, 2000)] public void ResizeBicubic(int width, int height) From 7a93ae42d976f5e1a2df5e3a729be6bb9bcd2eb4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 1 Mar 2020 00:15:36 +0100 Subject: [PATCH 035/213] AVX float -> byte conversion --- .../Helpers/SimdUtils.Avx2Intrinsics.cs | 99 ++++ src/ImageSharp/Common/Helpers/SimdUtils.cs | 6 +- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 6 +- .../ColorConverters/JpegColorConverter.cs | 2 +- .../Jpeg/BlockOperations/Block8x8F_Round.cs | 442 +++++++++++++++++- .../Codecs/Jpeg/YCbCrColorConversion.cs | 10 +- .../Color/Bulk/FromVector4.cs | 122 +++-- tests/ImageSharp.Benchmarks/Config.cs | 8 + .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 19 + .../Formats/Jpg/JpegColorConverterTests.cs | 2 +- 10 files changed, 668 insertions(+), 48 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs new file mode 100644 index 0000000000..85f73776c2 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs @@ -0,0 +1,99 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +#if SUPPORTS_RUNTIME_INTRINSICS + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + public static class Avx2Intrinsics + { + private static ReadOnlySpan PermuteMaskDeinterleave8x32 => new byte[] { 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0 }; + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (Avx2.IsSupported) + { + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + } + + /// + /// Implementation of , which is faster on new .NET runtime. + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) + { + VerifySpanInput(source, dest, Vector256.Count); + + int n = dest.Length / Vector256.Count; + + ref Vector256 sourceBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector256 destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + var maxBytes = Vector256.Create(255f); + ref byte maskBase = ref MemoryMarshal.GetReference(PermuteMaskDeinterleave8x32); + Vector256 mask = Unsafe.As>(ref maskBase); + + for (int i = 0; i < n; i++) + { + ref Vector256 s = ref Unsafe.Add(ref sourceBase, i * 4); + + Vector256 f0 = s; + Vector256 f1 = Unsafe.Add(ref s, 1); + Vector256 f2 = Unsafe.Add(ref s, 2); + Vector256 f3 = Unsafe.Add(ref s, 3); + + Vector256 w0 = ConvertToInt32(f0, maxBytes); + Vector256 w1 = ConvertToInt32(f1, maxBytes); + Vector256 w2 = ConvertToInt32(f2, maxBytes); + Vector256 w3 = ConvertToInt32(f3, maxBytes); + + Vector256 u0 = Avx2.PackSignedSaturate(w0, w1); + Vector256 u1 = Avx2.PackSignedSaturate(w2, w3); + Vector256 b = Avx2.PackUnsignedSaturate(u0, u1); + b = Avx2.PermuteVar8x32(b.AsInt32(), mask).AsByte(); + + Unsafe.Add(ref destBase, i) = b; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector256 ConvertToInt32(Vector256 vf, Vector256 scale) + { + vf = Avx.Multiply(vf, scale); + return Avx.ConvertToVector256Int32(vf); + } + } + } +} +#endif diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 08c256f842..de313c8d57 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -92,11 +92,15 @@ namespace SixLabors.ImageSharp { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); -#if SUPPORTS_EXTENDED_INTRINSICS +#if SUPPORTS_RUNTIME_INTRINSICS + Avx2Intrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#elif SUPPORTS_EXTENDED_INTRINSICS ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); #else BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); #endif + + // Also deals with the remainder from previous conversions: FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); // Deal with the remainder: diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index 1165db2802..8c1b427ee5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -13,9 +13,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { internal abstract partial class JpegColorConverter { - internal sealed class FromYCbCrSimdAvx2 : JpegColorConverter + internal sealed class FromYCbCrSimdVector8 : JpegColorConverter { - public FromYCbCrSimdAvx2(int precision) + public FromYCbCrSimdVector8(int precision) : base(JpegColorSpace.YCbCr, precision) { } @@ -107,4 +107,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 44314759ce..7ada1b9da4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// Returns the for the YCbCr colorspace that matches the current CPU architecture. /// private static JpegColorConverter GetYCbCrConverter(int precision) => - FromYCbCrSimdAvx2.IsAvailable ? (JpegColorConverter)new FromYCbCrSimdAvx2(precision) : new FromYCbCrSimd(precision); + FromYCbCrSimdVector8.IsAvailable ? (JpegColorConverter)new FromYCbCrSimdVector8(precision) : new FromYCbCrSimd(precision); /// /// A stack-only struct to reference the input buffers using -s. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs index bf6ea3dacf..32d838f8c4 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs @@ -4,6 +4,12 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif using BenchmarkDotNet.Attributes; @@ -12,10 +18,14 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { - public class Block8x8F_Round + public unsafe class Block8x8F_Round { private Block8x8F block; + private readonly byte[] blockBuffer = new byte[512]; + private GCHandle blockHandle; + private float* alignedPtr; + [GlobalSetup] public void Setup() { @@ -24,13 +34,27 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations throw new NotSupportedException("Vector.Count != 8"); } - for (int i = 0; i < Block8x8F.Size; i++) + this.blockHandle = GCHandle.Alloc(this.blockBuffer, GCHandleType.Pinned); + ulong ptr = (ulong)this.blockHandle.AddrOfPinnedObject(); + ptr += 16; + ptr -= ptr % 16; + + if (ptr % 16 != 0) { - this.block[i] = i * 44.8f; + throw new Exception("ptr is unaligned"); } + + this.alignedPtr = (float*)ptr; } - [Benchmark(Baseline = true)] + [GlobalCleanup] + public void Cleanup() + { + this.blockHandle.Free(); + this.alignedPtr = null; + } + + [Benchmark] public void ScalarRound() { ref float b = ref Unsafe.As(ref this.block); @@ -42,8 +66,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations } } - [Benchmark] - public void SimdRound() + [Benchmark(Baseline = true)] + public void SimdUtils_FastRound_Vector8() { ref Block8x8F b = ref this.block; @@ -64,5 +88,411 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations ref Vector row7 = ref Unsafe.As>(ref b.V7L); row7 = SimdUtils.FastRound(row7); } + + [Benchmark] + public void SimdUtils_FastRound_Vector8_ForceAligned() + { + ref Block8x8F b = ref Unsafe.AsRef(this.alignedPtr); + + ref Vector row0 = ref Unsafe.As>(ref b.V0L); + row0 = SimdUtils.FastRound(row0); + ref Vector row1 = ref Unsafe.As>(ref b.V1L); + row1 = SimdUtils.FastRound(row1); + ref Vector row2 = ref Unsafe.As>(ref b.V2L); + row2 = SimdUtils.FastRound(row2); + ref Vector row3 = ref Unsafe.As>(ref b.V3L); + row3 = SimdUtils.FastRound(row3); + ref Vector row4 = ref Unsafe.As>(ref b.V4L); + row4 = SimdUtils.FastRound(row4); + ref Vector row5 = ref Unsafe.As>(ref b.V5L); + row5 = SimdUtils.FastRound(row5); + ref Vector row6 = ref Unsafe.As>(ref b.V6L); + row6 = SimdUtils.FastRound(row6); + ref Vector row7 = ref Unsafe.As>(ref b.V7L); + row7 = SimdUtils.FastRound(row7); + } + + [Benchmark] + public void SimdUtils_FastRound_Vector8_Grouped() + { + ref Block8x8F b = ref this.block; + + ref Vector row0 = ref Unsafe.As>(ref b.V0L); + ref Vector row1 = ref Unsafe.As>(ref b.V1L); + ref Vector row2 = ref Unsafe.As>(ref b.V2L); + ref Vector row3 = ref Unsafe.As>(ref b.V3L); + + row0 = SimdUtils.FastRound(row0); + row1 = SimdUtils.FastRound(row1); + row2 = SimdUtils.FastRound(row2); + row3 = SimdUtils.FastRound(row3); + + row0 = ref Unsafe.As>(ref b.V4L); + row1 = ref Unsafe.As>(ref b.V5L); + row2 = ref Unsafe.As>(ref b.V6L); + row3 = ref Unsafe.As>(ref b.V7L); + + row0 = SimdUtils.FastRound(row0); + row1 = SimdUtils.FastRound(row1); + row2 = SimdUtils.FastRound(row2); + row3 = SimdUtils.FastRound(row3); + } + +#if SUPPORTS_RUNTIME_INTRINSICS + [Benchmark] + public void Sse41_V1() + { + ref Vector128 b0 = ref Unsafe.As>(ref this.block); + + ref Vector128 p = ref b0; + p = Sse41.RoundToNearestInteger(p); + + p = ref Unsafe.Add(ref b0, 1); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 2); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 3); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 4); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 5); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 6); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 7); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 8); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 9); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 10); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 11); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 12); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 13); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 14); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.Add(ref b0, 15); + p = Sse41.RoundToNearestInteger(p); + } + + [Benchmark] + public unsafe void Sse41_V2() + { + ref Vector128 p = ref Unsafe.As>(ref this.block); + p = Sse41.RoundToNearestInteger(p); + var offset = (IntPtr)sizeof(Vector128); + p = Sse41.RoundToNearestInteger(p); + + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + } + + [Benchmark] + public unsafe void Sse41_V3() + { + ref Vector128 p = ref Unsafe.As>(ref this.block); + p = Sse41.RoundToNearestInteger(p); + var offset = (IntPtr)sizeof(Vector128); + + for (int i = 0; i < 15; i++) + { + p = ref Unsafe.AddByteOffset(ref p, offset); + p = Sse41.RoundToNearestInteger(p); + } + } + + [Benchmark] + public unsafe void Sse41_V4() + { + ref Vector128 p = ref Unsafe.As>(ref this.block); + var offset = (IntPtr)sizeof(Vector128); + + ref Vector128 a = ref p; + ref Vector128 b = ref Unsafe.AddByteOffset(ref a, offset); + ref Vector128 c = ref Unsafe.AddByteOffset(ref b, offset); + ref Vector128 d = ref Unsafe.AddByteOffset(ref c, offset); + a = Sse41.RoundToNearestInteger(a); + b = Sse41.RoundToNearestInteger(b); + c = Sse41.RoundToNearestInteger(c); + d = Sse41.RoundToNearestInteger(d); + + a = ref Unsafe.AddByteOffset(ref d, offset); + b = ref Unsafe.AddByteOffset(ref a, offset); + c = ref Unsafe.AddByteOffset(ref b, offset); + d = ref Unsafe.AddByteOffset(ref c, offset); + a = Sse41.RoundToNearestInteger(a); + b = Sse41.RoundToNearestInteger(b); + c = Sse41.RoundToNearestInteger(c); + d = Sse41.RoundToNearestInteger(d); + + a = ref Unsafe.AddByteOffset(ref d, offset); + b = ref Unsafe.AddByteOffset(ref a, offset); + c = ref Unsafe.AddByteOffset(ref b, offset); + d = ref Unsafe.AddByteOffset(ref c, offset); + a = Sse41.RoundToNearestInteger(a); + b = Sse41.RoundToNearestInteger(b); + c = Sse41.RoundToNearestInteger(c); + d = Sse41.RoundToNearestInteger(d); + + a = ref Unsafe.AddByteOffset(ref d, offset); + b = ref Unsafe.AddByteOffset(ref a, offset); + c = ref Unsafe.AddByteOffset(ref b, offset); + d = ref Unsafe.AddByteOffset(ref c, offset); + a = Sse41.RoundToNearestInteger(a); + b = Sse41.RoundToNearestInteger(b); + c = Sse41.RoundToNearestInteger(c); + d = Sse41.RoundToNearestInteger(d); + } + + [Benchmark] + public unsafe void Sse41_V5_Unaligned() + { + float* p = this.alignedPtr + 1; + + Vector128 v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + p += 8; + + v = Sse.LoadVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.Store(p, v); + } + + [Benchmark] + public unsafe void Sse41_V5_Aligned() + { + float* p = this.alignedPtr; + + Vector128 v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + + v = Sse.LoadAlignedVector128(p); + v = Sse41.RoundToNearestInteger(v); + Sse.StoreAligned(p, v); + p += 8; + } + + [Benchmark] + public void Sse41_V6_Aligned() + { + float* p = this.alignedPtr; + + Round8SseVectors(p); + Round8SseVectors(p + 32); + } + + private static void Round8SseVectors(float* p0) + { + float* p1 = p0 + 4; + float* p2 = p1 + 4; + float* p3 = p2 + 4; + float* p4 = p3 + 4; + float* p5 = p4 + 4; + float* p6 = p5 + 4; + float* p7 = p6 + 4; + + Vector128 v0 = Sse.LoadAlignedVector128(p0); + Vector128 v1 = Sse.LoadAlignedVector128(p1); + Vector128 v2 = Sse.LoadAlignedVector128(p2); + Vector128 v3 = Sse.LoadAlignedVector128(p3); + Vector128 v4 = Sse.LoadAlignedVector128(p4); + Vector128 v5 = Sse.LoadAlignedVector128(p5); + Vector128 v6 = Sse.LoadAlignedVector128(p6); + Vector128 v7 = Sse.LoadAlignedVector128(p7); + + v0 = Sse41.RoundToNearestInteger(v0); + v1 = Sse41.RoundToNearestInteger(v1); + v2 = Sse41.RoundToNearestInteger(v2); + v3 = Sse41.RoundToNearestInteger(v3); + v4 = Sse41.RoundToNearestInteger(v4); + v5 = Sse41.RoundToNearestInteger(v5); + v6 = Sse41.RoundToNearestInteger(v6); + v7 = Sse41.RoundToNearestInteger(v7); + + Sse.StoreAligned(p0, v0); + Sse.StoreAligned(p1, v1); + Sse.StoreAligned(p2, v2); + Sse.StoreAligned(p3, v3); + Sse.StoreAligned(p4, v4); + Sse.StoreAligned(p5, v5); + Sse.StoreAligned(p6, v6); + Sse.StoreAligned(p7, v7); + } +#endif } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs index 1e4ebb7196..f8e7f7fb80 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs @@ -11,7 +11,7 @@ using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { - [Config(typeof(Config.ShortClr))] + [Config(typeof(Config.ShortCore31))] public class YCbCrColorConversion { private Buffer2D[] input; @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } } - [Benchmark(Baseline = true)] + [Benchmark] public void Scalar() { var values = new JpegColorConverter.ComponentValues(this.input, 0); @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg JpegColorConverter.FromYCbCrBasic.ConvertCore(values, this.output, 255F, 128F); } - [Benchmark] + [Benchmark(Baseline = true)] public void SimdVector4() { var values = new JpegColorConverter.ComponentValues(this.input, 0); @@ -53,11 +53,11 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg } [Benchmark] - public void SimdAvx2() + public void SimdVector8() { var values = new JpegColorConverter.ComponentValues(this.input, 0); - JpegColorConverter.FromYCbCrSimdAvx2.ConvertCore(values, this.output, 255F, 128F); + JpegColorConverter.FromYCbCrSimdVector8.ConvertCore(values, this.output, 255F, 128F); } private static Buffer2D[] CreateRandomValues( diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index f2af362e04..04043c2f7b 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -7,15 +7,21 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using BenchmarkDotNet.Attributes; +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Environments; +using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - [Config(typeof(Config.ShortClr))] + [Config(typeof(Config.ShortCore31))] public abstract class FromVector4 where TPixel : unmanaged, IPixel { @@ -25,7 +31,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk protected Configuration Configuration => Configuration.Default; - [Params(64, 2048)] + // [Params(64, 2048)] + [Params(1024)] public int Count { get; set; } [GlobalSetup] @@ -77,7 +84,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } - [Benchmark(Baseline = true)] + [Benchmark] public void BasicIntrinsics256() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -86,7 +93,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } - [Benchmark] + [Benchmark(Baseline = true)] public void ExtendedIntrinsic() { Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); @@ -95,31 +102,84 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); } - // RESULTS (2018 October): - // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | - // ---------------------------- |-------- |------ |-------------:|-------------:|------------:|-------:|---------:|-------:|----------:| - // FallbackIntrinsics128 | Clr | 64 | 340.38 ns | 22.319 ns | 1.2611 ns | 1.41 | 0.01 | - | 0 B | - // BasicIntrinsics256 | Clr | 64 | 240.79 ns | 11.421 ns | 0.6453 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic | Clr | 64 | 199.09 ns | 124.239 ns | 7.0198 ns | 0.83 | 0.02 | - | 0 B | - // PixelOperations_Base | Clr | 64 | 647.99 ns | 24.003 ns | 1.3562 ns | 2.69 | 0.01 | 0.0067 | 24 B | - // PixelOperations_Specialized | Clr | 64 | 259.79 ns | 13.391 ns | 0.7566 ns | 1.08 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! - // | | | | | | | | | | - // FallbackIntrinsics128 | Core | 64 | 234.64 ns | 12.320 ns | 0.6961 ns | 1.58 | 0.00 | - | 0 B | - // BasicIntrinsics256 | Core | 64 | 148.87 ns | 2.794 ns | 0.1579 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic | Core | 64 | 94.06 ns | 10.015 ns | 0.5659 ns | 0.63 | 0.00 | - | 0 B | - // PixelOperations_Base | Core | 64 | 573.52 ns | 31.865 ns | 1.8004 ns | 3.85 | 0.01 | 0.0067 | 24 B | - // PixelOperations_Specialized | Core | 64 | 117.21 ns | 13.264 ns | 0.7494 ns | 0.79 | 0.00 | - | 0 B | - // | | | | | | | | | | - // FallbackIntrinsics128 | Clr | 2048 | 6,735.93 ns | 2,139.340 ns | 120.8767 ns | 1.71 | 0.03 | - | 0 B | - // BasicIntrinsics256 | Clr | 2048 | 3,929.29 ns | 334.027 ns | 18.8731 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic | Clr | 2048 | 2,226.01 ns | 130.525 ns | 7.3749 ns |!! 0.57 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! - // PixelOperations_Base | Clr | 2048 | 16,760.84 ns | 367.800 ns | 20.7814 ns | 4.27 | 0.02 | - | 24 B | <--- Extra copies using "Vector4 TPixel.ToVector4()" - // PixelOperations_Specialized | Clr | 2048 | 3,986.03 ns | 237.238 ns | 13.4044 ns | 1.01 | 0.00 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( - // | | | | | | | | | | - // FallbackIntrinsics128 | Core | 2048 | 6,644.65 ns | 2,677.090 ns | 151.2605 ns | 1.69 | 0.05 | - | 0 B | - // BasicIntrinsics256 | Core | 2048 | 3,923.70 ns | 1,971.760 ns | 111.4081 ns | 1.00 | 0.00 | - | 0 B | - // ExtendedIntrinsic | Core | 2048 | 2,092.32 ns | 375.657 ns | 21.2253 ns |!! 0.53 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! - // PixelOperations_Base | Core | 2048 | 16,875.73 ns | 1,271.957 ns | 71.8679 ns | 4.30 | 0.10 | - | 24 B | - // PixelOperations_Specialized | Core | 2048 | 2,129.92 ns | 262.888 ns | 14.8537 ns |!! 0.54 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! +#if SUPPORTS_RUNTIME_INTRINSICS + [Benchmark] + public void UseAvx2() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.Avx2Intrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + + private static ReadOnlySpan PermuteMaskDeinterleave8x32 => new byte[] { 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0 }; + + [Benchmark] + public void UseAvx2_Grouped() + { + Span src = MemoryMarshal.Cast(this.source.GetSpan()); + Span dest = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dest.Length / Vector.Count; + + ref Vector256 sourceBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(src)); + ref Vector256 destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + ref byte maskBase = ref MemoryMarshal.GetReference(PermuteMaskDeinterleave8x32); + Vector256 mask = Unsafe.As>(ref maskBase); + + var maxBytes = Vector256.Create(255f); + + for (int i = 0; i < n; i++) + { + ref Vector256 s = ref Unsafe.Add(ref sourceBase, i * 4); + + Vector256 f0 = s; + Vector256 f1 = Unsafe.Add(ref s, 1); + Vector256 f2 = Unsafe.Add(ref s, 2); + Vector256 f3 = Unsafe.Add(ref s, 3); + + f0 = Avx.Multiply(maxBytes, f0); + f1 = Avx.Multiply(maxBytes, f1); + f2 = Avx.Multiply(maxBytes, f2); + f3 = Avx.Multiply(maxBytes, f3); + + Vector256 w0 = Avx.ConvertToVector256Int32(f0); + Vector256 w1 = Avx.ConvertToVector256Int32(f1); + Vector256 w2 = Avx.ConvertToVector256Int32(f2); + Vector256 w3 = Avx.ConvertToVector256Int32(f3); + + Vector256 u0 = Avx2.PackSignedSaturate(w0, w1); + Vector256 u1 = Avx2.PackSignedSaturate(w2, w3); + Vector256 b = Avx2.PackUnsignedSaturate(u0, u1); + b = Avx2.PermuteVar8x32(b.AsInt32(), mask).AsByte(); + + Unsafe.Add(ref destBase, i) = b; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector256 ConvertToInt32(Vector256 vf, Vector256 scale) + { + vf = Avx.Multiply(scale, vf); + return Avx.ConvertToVector256Int32(vf); + } +#endif + + // *** RESULTS 2020 March: *** + // Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores + // .NET Core SDK=3.1.200-preview-014971 + // Job-IUZXZT : .NET Core 3.1.2 (CoreCLR 4.700.20.6602, CoreFX 4.700.20.6702), X64 RyuJIT + // + // | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | + // |---------------------------- |------ |-----------:|------------:|----------:|------:|--------:|------:|------:|------:|----------:| + // | FallbackIntrinsics128 | 1024 | 2,952.6 ns | 1,680.77 ns | 92.13 ns | 3.32 | 0.16 | - | - | - | - | + // | BasicIntrinsics256 | 1024 | 1,664.5 ns | 928.11 ns | 50.87 ns | 1.87 | 0.09 | - | - | - | - | + // | ExtendedIntrinsic | 1024 | 890.6 ns | 375.48 ns | 20.58 ns | 1.00 | 0.00 | - | - | - | - | + // | UseAvx2 | 1024 | 299.0 ns | 30.47 ns | 1.67 ns | 0.34 | 0.01 | - | - | - | - | + // | UseAvx2_Grouped | 1024 | 318.1 ns | 48.19 ns | 2.64 ns | 0.36 | 0.01 | - | - | - | - | + // | PixelOperations_Base | 1024 | 8,136.9 ns | 1,834.82 ns | 100.57 ns | 9.14 | 0.26 | - | - | - | 24 B | + // | PixelOperations_Specialized | 1024 | 951.1 ns | 123.93 ns | 6.79 ns | 1.07 | 0.03 | - | - | - | - | } } diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index fd0b213b39..fda98a097c 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -38,6 +38,14 @@ namespace SixLabors.ImageSharp.Benchmarks } } + public class ShortCore31 : Config + { + public ShortCore31() + { + this.Add(Job.Default.With(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3)); + } + } + #if Windows_NT private bool IsElevated { diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index cc5519c795..1ab854c009 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using SixLabors.ImageSharp.Common.Tuples; using Xunit; @@ -277,6 +278,24 @@ namespace SixLabors.ImageSharp.Tests.Common Assert.Equal(expected2, actual2); } +#if SUPPORTS_RUNTIME_INTRINSICS + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy32))] + public void Avx2_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + if (!System.Runtime.Intrinsics.X86.Avx2.IsSupported) + { + return; + } + + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + count, + (s, d) => SimdUtils.Avx2Intrinsics.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span)); + } + +#endif + [Theory] [MemberData(nameof(ArbitraryArraySizes))] public void BulkConvertNormalizedFloatToByteClampOverflows(int count) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 7f0033cc5c..27c612aee8 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg // JpegColorConverter.FromYCbCrSimdAvx2.LogPlz = s => this.Output.WriteLine(s); ValidateRgbToYCbCrConversion( - new JpegColorConverter.FromYCbCrSimdAvx2(8), + new JpegColorConverter.FromYCbCrSimdVector8(8), 3, inputBufferLength, resultBufferLength, From 89529541498f20aabe90a13786503adf8cff197e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 1 Mar 2020 22:27:49 +1100 Subject: [PATCH 036/213] Better performance --- .../DiscontiguousBuffers/IMemoryGroup{T}.cs | 4 +- .../Processors/Dithering/ErrorDither.cs | 2 +- .../IPaletteDitherImageProcessor{TPixel}.cs | 4 +- .../Dithering/OrderedDither.KnownTypes.cs | 2 +- .../Processors/Dithering/OrderedDither.cs | 4 +- .../PaletteDitherProcessor{TPixel}.cs | 2 +- .../Quantization/EuclideanPixelMap{TPixel}.cs | 36 +++++++++--------- .../Quantization/FrameQuantizerExtensions.cs | 2 +- .../OctreeFrameQuantizer{TPixel}.cs | 2 +- .../Quantization/OctreeQuantizer.cs | 4 +- .../PaletteFrameQuantizer{TPixel}.cs | 4 +- .../Quantization/PaletteQuantizer.cs | 3 +- .../Quantization/WebSafePaletteQuantizer.cs | 4 +- .../Quantization/WernerPaletteQuantizer.cs | 4 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 38 +++++++++---------- .../Processors/Quantization/WuQuantizer.cs | 4 +- 16 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs index 2649b7fb16..89aca914d0 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs @@ -18,12 +18,12 @@ namespace SixLabors.ImageSharp.Memory /// Gets the number of elements per contiguous sub-buffer preceding the last buffer. /// The last buffer is allowed to be smaller. /// - public int BufferLength { get; } + int BufferLength { get; } /// /// Gets the aggregate number of elements in the group. /// - public long TotalLength { get; } + long TotalLength { get; } /// /// Gets a value indicating whether the group has been invalidated. diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 9217d1c3f7..6aa6eeca69 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering for (int x = bounds.Left; x < bounds.Right; x++) { TPixel sourcePixel = row[x]; - TPixel transformed = processor.GetPaletteColor(sourcePixel, palette); + TPixel transformed = Unsafe.AsRef(processor).GetPaletteColor(sourcePixel, palette); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); row[x] = transformed; } diff --git a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs index 3e4bf4d836..a890e929dc 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs @@ -14,9 +14,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering where TPixel : unmanaged, IPixel { /// - /// Gets the configration instance to use when performing operations. + /// Gets the configuration instance to use when performing operations. /// - public Configuration Configuration { get; } + Configuration Configuration { get; } /// /// Gets the dithering palette. diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs index d3e7107826..f6026a64f7 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// An ordered dithering matrix with equal sides of arbitrary length /// - public readonly partial struct OrderedDither : IDither + public readonly partial struct OrderedDither { /// /// Applies order dithering using the 2x2 Bayer dithering matrix. diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index c5b4135f56..9e97fe7e65 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -237,7 +237,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering for (int x = this.bounds.Left; x < this.bounds.Right; x++) { TPixel dithered = this.dither.Dither(sourceRow[x], x, y, this.bitDepth, scale); - destinationRow[x - offsetX] = this.quantizer.GetQuantizedColor(dithered, paletteSpan, out TPixel _); + destinationRow[x - offsetX] = Unsafe.AsRef(this.quantizer).GetQuantizedColor(dithered, paletteSpan, out TPixel _); } } } @@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering { ref TPixel sourcePixel = ref row[x]; TPixel dithered = this.dither.Dither(sourcePixel, x, y, this.bitDepth, this.scale); - sourcePixel = this.processor.GetPaletteColor(dithered, paletteSpan); + sourcePixel = Unsafe.AsRef(this.processor).GetPaletteColor(dithered, paletteSpan); } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index d25048a7f7..4d4ccf1ab4 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering float ditherScale) { this.Configuration = configuration; - this.pixelMap = new EuclideanPixelMap(palette); + this.pixelMap = new EuclideanPixelMap(configuration, palette); this.Palette = palette; this.DitherScale = ditherScale; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 615a7238b8..7147886297 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Concurrent; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Quantization @@ -17,27 +18,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization internal readonly struct EuclideanPixelMap : IPixelMap, IEquatable> where TPixel : unmanaged, IPixel { - private readonly ConcurrentDictionary vectorCache; + private readonly Vector4[] vectorCache; private readonly ConcurrentDictionary distanceCache; /// /// Initializes a new instance of the struct. /// + /// The configuration. /// The color palette to map from. [MethodImpl(InliningOptions.ShortMethod)] - public EuclideanPixelMap(ReadOnlyMemory palette) + public EuclideanPixelMap(Configuration configuration, ReadOnlyMemory palette) { Guard.MustBeGreaterThan(palette.Length, 0, nameof(palette)); this.Palette = palette; ReadOnlySpan paletteSpan = this.Palette.Span; - this.vectorCache = new ConcurrentDictionary(); + this.vectorCache = new Vector4[paletteSpan.Length]; this.distanceCache = new ConcurrentDictionary(); - for (int i = 0; i < paletteSpan.Length; i++) - { - this.vectorCache[i] = paletteSpan[i].ToScaledVector4(); - } + PixelOperations.Instance.ToVector4(configuration, paletteSpan, this.vectorCache); } /// @@ -81,31 +80,32 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization int index = 0; float leastDistance = float.MaxValue; Vector4 vector = color.ToScaledVector4(); + ref TPixel paletteRef = ref MemoryMarshal.GetReference(palette); + ref Vector4 vectorCacheRef = ref MemoryMarshal.GetReference(this.vectorCache); for (int i = 0; i < palette.Length; i++) { - Vector4 candidate = this.vectorCache[i]; + Vector4 candidate = Unsafe.Add(ref vectorCacheRef, i); float distance = Vector4.DistanceSquared(vector, candidate); - if (!(distance < leastDistance)) + // If it's an exact match, exit the loop + if (distance == 0) { - continue; + index = i; + break; } - // Less than... assign. - index = i; - leastDistance = distance; - - // And if it's an exact match, exit the loop - if (distance == 0) + if (distance < leastDistance) { - break; + // Less than... assign. + index = i; + leastDistance = distance; } } // Now I have the index, pop it into the cache for next time this.distanceCache[color] = index; - match = palette[index]; + match = Unsafe.Add(ref paletteRef, index); return index; } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs index d6d8b98dae..ef97f57e3d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - destinationRow[x - offsetX] = this.quantizer.GetQuantizedColor(sourceRow[x], paletteSpan, out TPixel _); + destinationRow[x - offsetX] = Unsafe.AsRef(this.quantizer).GetQuantizedColor(sourceRow[x], paletteSpan, out TPixel _); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 946ae399bb..e80449b09f 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.octree.Palletize(paletteSpan, this.colors); // TODO: Cannot make method readonly due to this line. - this.pixelMap = new EuclideanPixelMap(this.palette.Memory); + this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory); return paletteSpan; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 3328fd6c7c..9e04edef0b 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -11,12 +11,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class OctreeQuantizer : IQuantizer { + private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions(); + /// /// Initializes a new instance of the class /// using the default . /// public OctreeQuantizer() - : this(new QuantizerOptions()) + : this(DefaultOptions) { } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index 7960f728af..3dbf77a3a9 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.paletteOwner = configuration.MemoryAllocator.Allocate(maxLength); Color.ToPixel(configuration, colors, this.paletteOwner.GetSpan()); - this.pixelMap = new EuclideanPixelMap(this.paletteOwner.Memory); + this.pixelMap = new EuclideanPixelMap(configuration, this.paletteOwner.Memory); this.isDisposed = false; } @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.paletteOwner = configuration.MemoryAllocator.Allocate(maxLength); palette.CopyTo(this.paletteOwner.GetSpan()); - this.pixelMap = new EuclideanPixelMap(this.paletteOwner.Memory); + this.pixelMap = new EuclideanPixelMap(configuration, this.paletteOwner.Memory); this.isDisposed = false; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 75a0f39389..e95f8c5db5 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class PaletteQuantizer : IQuantizer { + private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions(); private readonly ReadOnlyMemory palette; /// @@ -18,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The color palette. public PaletteQuantizer(ReadOnlyMemory palette) - : this(palette, new QuantizerOptions()) + : this(palette, DefaultOptions) { } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs index 8aa634b9ff..d95ed5aab9 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs @@ -10,11 +10,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class WebSafePaletteQuantizer : PaletteQuantizer { + private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions(); + /// /// Initializes a new instance of the class. /// public WebSafePaletteQuantizer() - : this(new QuantizerOptions()) + : this(DefaultOptions) { } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs index 168c837d57..8f8e38dd9d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs @@ -9,11 +9,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class WernerPaletteQuantizer : PaletteQuantizer { + private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions(); + /// /// Initializes a new instance of the class. /// public WernerPaletteQuantizer() - : this(new QuantizerOptions()) + : this(DefaultOptions) { } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 5054772582..6f98ce121e 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -132,30 +132,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // TODO: Cannot make methods readonly due to this line. - this.pixelMap = new EuclideanPixelMap(this.palette.Memory); + this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory); return paletteSpan; } /// public readonly byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) { - if (!this.isDithering) + if (this.isDithering) { - Rgba32 rgba = default; - color.ToRgba32(ref rgba); - - int r = rgba.R >> (8 - IndexBits); - int g = rgba.G >> (8 - IndexBits); - int b = rgba.B >> (8 - IndexBits); - int a = rgba.A >> (8 - IndexAlphaBits); - - ReadOnlySpan tagSpan = this.tag.GetSpan(); - byte index = tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)]; - match = palette[index]; - return index; + return (byte)this.pixelMap.GetClosestColor(color, out match); } - return (byte)this.pixelMap.GetClosestColor(color, out match); + Rgba32 rgba = default; + color.ToRgba32(ref rgba); + + int r = rgba.R >> (8 - IndexBits); + int g = rgba.G >> (8 - IndexBits); + int b = rgba.B >> (8 - IndexBits); + int a = rgba.A >> (8 - IndexAlphaBits); + + ReadOnlySpan tagSpan = this.tag.GetSpan(); + byte index = tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)]; + match = palette[index]; + return index; } /// @@ -376,11 +376,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box. /// - /// The memory allocator used for allocating buffers. - private void Get3DMoments(MemoryAllocator memoryAllocator) + /// The memory allocator used for allocating buffers. + private void Get3DMoments(MemoryAllocator allocator) { - using IMemoryOwner volume = memoryAllocator.Allocate(IndexCount * IndexAlphaCount); - using IMemoryOwner area = memoryAllocator.Allocate(IndexAlphaCount); + using IMemoryOwner volume = allocator.Allocate(IndexCount * IndexAlphaCount); + using IMemoryOwner area = allocator.Allocate(IndexAlphaCount); Span momentSpan = this.moments.GetSpan(); Span volumeSpan = volume.GetSpan(); diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 872e6d5bd4..d2e33aa1f1 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -10,12 +10,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class WuQuantizer : IQuantizer { + private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions(); + /// /// Initializes a new instance of the class /// using the default . /// public WuQuantizer() - : this(new QuantizerOptions()) + : this(DefaultOptions) { } From 63f277b404b82e0f4bfaaada15f6a938850d9b2a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 3 Mar 2020 23:25:56 +1100 Subject: [PATCH 037/213] Simplify, fix color mapping, and refactor for performance. --- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 6 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 24 +++++-- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- .../Processors/Dithering/ErrorDither.cs | 19 +++--- .../IPaletteDitherImageProcessor{TPixel}.cs | 3 +- .../Processors/Dithering/OrderedDither.cs | 17 +++-- .../PaletteDitherProcessor{TPixel}.cs | 9 ++- .../Quantization/EuclideanPixelMap{TPixel}.cs | 68 +++++++++---------- .../Quantization/FrameQuantizerExtensions.cs | 12 ++-- .../Quantization/IFrameQuantizer{TPixel}.cs | 3 +- .../Quantization/IPixelMap{TPixel}.cs | 30 -------- .../OctreeFrameQuantizer{TPixel}.cs | 26 ++++--- .../PaletteFrameQuantizer{TPixel}.cs | 53 +++------------ .../Quantization/PaletteQuantizer.cs | 14 +++- .../Quantization/QuantizeProcessor{TPixel}.cs | 2 +- .../Quantization/QuantizedFrame{TPixel}.cs | 4 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 10 +-- .../Formats/Gif/GifEncoderTests.cs | 18 +++++ .../Quantization/QuantizedImageTests.cs | 2 +- .../Quantization/WuQuantizerTests.cs | 8 +-- 20 files changed, 154 insertions(+), 176 deletions(-) delete mode 100644 src/ImageSharp/Processing/Processors/Quantization/IPixelMap{TPixel}.cs diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index ed5ed42933..3d5854ce57 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -336,10 +336,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp private void Write8BitColor(Stream stream, ImageFrame image, Span colorPalette) where TPixel : unmanaged, IPixel { - using IFrameQuantizer quantizer = this.quantizer.CreateFrameQuantizer(this.configuration); - using QuantizedFrame quantized = quantizer.QuantizeFrame(image, image.Bounds()); + using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration); + using QuantizedFrame quantized = frameQuantizer.QuantizeFrame(image, image.Bounds()); - ReadOnlySpan quantizedColors = quantized.Palette; + ReadOnlySpan quantizedColors = quantized.Palette.Span; var color = default(Rgba32); // TODO: Use bulk conversion here for better perf diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 87317a3ef5..dc74353e39 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -128,6 +128,11 @@ namespace SixLabors.ImageSharp.Formats.Gif private void EncodeGlobal(Image image, QuantizedFrame quantized, int transparencyIndex, Stream stream) where TPixel : unmanaged, IPixel { + // The palette quantizer can reuse the same pixel map across multiple frames + // since the palette is unchanging. This allows a reduction of memory usage across + // multi frame gifs using a global palette. + EuclideanPixelMap pixelMap = default; + bool pixelMapSet = false; for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; @@ -142,7 +147,13 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using var paletteFrameQuantizer = new PaletteFrameQuantizer(this.configuration, this.quantizer.Options, quantized.Palette); + if (!pixelMapSet) + { + pixelMapSet = true; + pixelMap = new EuclideanPixelMap(this.configuration, quantized.Palette, quantized.Palette.Span.Length); + } + + using var paletteFrameQuantizer = new PaletteFrameQuantizer(this.configuration, this.quantizer.Options, pixelMap); using QuantizedFrame paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds()); this.WriteImageData(paletteQuantized, stream); } @@ -214,7 +225,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan); + PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette.Span, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { @@ -321,8 +332,9 @@ namespace SixLabors.ImageSharp.Formats.Gif return; } - foreach (string comment in metadata.Comments) + for (var i = 0; i < metadata.Comments.Count; i++) { + string comment = metadata.Comments[i]; this.buffer[0] = GifConstants.ExtensionIntroducer; this.buffer[1] = GifConstants.CommentLabel; stream.Write(this.buffer, 0, 2); @@ -330,7 +342,9 @@ namespace SixLabors.ImageSharp.Formats.Gif // Comment will be stored in chunks of 255 bytes, if it exceeds this size. ReadOnlySpan commentSpan = comment.AsSpan(); int idx = 0; - for (; idx <= comment.Length - GifConstants.MaxCommentSubBlockLength; idx += GifConstants.MaxCommentSubBlockLength) + for (; + idx <= comment.Length - GifConstants.MaxCommentSubBlockLength; + idx += GifConstants.MaxCommentSubBlockLength) { WriteCommentSubBlock(stream, commentSpan, idx, GifConstants.MaxCommentSubBlockLength); } @@ -443,7 +457,7 @@ namespace SixLabors.ImageSharp.Formats.Gif using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength); PixelOperations.Instance.ToRgb24Bytes( this.configuration, - image.Palette, + image.Palette.Span, colorTable.GetSpan(), pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index ed2fe143bb..ce624f768a 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -555,7 +555,7 @@ namespace SixLabors.ImageSharp.Formats.Png } // Grab the palette and write it to the stream. - ReadOnlySpan palette = quantized.Palette; + ReadOnlySpan palette = quantized.Palette.Span; int paletteLength = Math.Min(palette.Length, 256); int colorTableLength = paletteLength * 3; bool anyAlpha = false; diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 6aa6eeca69..9d0c563da4 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -95,20 +96,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering where TFrameQuantizer : struct, IFrameQuantizer where TPixel : unmanaged, IPixel { - ReadOnlySpan paletteSpan = destination.Palette; int offsetY = bounds.Top; int offsetX = bounds.Left; float scale = quantizer.Options.DitherScale; for (int y = bounds.Top; y < bounds.Bottom; y++) { - Span sourceRow = source.GetPixelRowSpan(y); - Span destinationRow = destination.GetPixelRowSpan(y - offsetY); + ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(source.GetPixelRowSpan(y)); + ref byte destinationRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y - offsetY)); for (int x = bounds.Left; x < bounds.Right; x++) { - TPixel sourcePixel = sourceRow[x]; - destinationRow[x - offsetX] = quantizer.GetQuantizedColor(sourcePixel, paletteSpan, out TPixel transformed); + TPixel sourcePixel = Unsafe.Add(ref sourceRowRef, x); + Unsafe.Add(ref destinationRowRef, x - offsetX) = quantizer.GetQuantizedColor(sourcePixel, out TPixel transformed); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); } } @@ -124,16 +124,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering where TPixel : unmanaged, IPixel { float scale = processor.DitherScale; - ReadOnlySpan palette = processor.Palette.Span; for (int y = bounds.Top; y < bounds.Bottom; y++) { - Span row = source.GetPixelRowSpan(y); + ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(source.GetPixelRowSpan(y)); for (int x = bounds.Left; x < bounds.Right; x++) { - TPixel sourcePixel = row[x]; - TPixel transformed = Unsafe.AsRef(processor).GetPaletteColor(sourcePixel, palette); + ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, x); + TPixel transformed = Unsafe.AsRef(processor).GetPaletteColor(sourcePixel); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); - row[x] = transformed; + sourcePixel = transformed; } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs index a890e929dc..a8e08fa3fa 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs @@ -32,8 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// Returns the color from the dithering palette corresponding to the given color. /// /// The color to match. - /// The output color palette. /// The match. - TPixel GetPaletteColor(TPixel color, ReadOnlySpan palette); + TPixel GetPaletteColor(TPixel color); } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 9e97fe7e65..64fe230f36 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -224,20 +225,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { - ReadOnlySpan paletteSpan = this.destination.Palette; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; float scale = this.quantizer.Options.DitherScale; for (int y = rows.Min; y < rows.Max; y++) { - Span sourceRow = this.source.GetPixelRowSpan(y); - Span destinationRow = this.destination.GetPixelRowSpan(y - offsetY); + ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); + ref byte destinationRowRef = ref MemoryMarshal.GetReference(this.destination.GetPixelRowSpan(y - offsetY)); for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - TPixel dithered = this.dither.Dither(sourceRow[x], x, y, this.bitDepth, scale); - destinationRow[x - offsetX] = Unsafe.AsRef(this.quantizer).GetQuantizedColor(dithered, paletteSpan, out TPixel _); + TPixel dithered = this.dither.Dither(Unsafe.Add(ref sourceRowRef, x), x, y, this.bitDepth, scale); + Unsafe.Add(ref destinationRowRef, x - offsetX) = Unsafe.AsRef(this.quantizer).GetQuantizedColor(dithered, out TPixel _); } } } @@ -272,16 +272,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { - ReadOnlySpan paletteSpan = this.processor.Palette.Span; for (int y = rows.Min; y < rows.Max; y++) { - Span row = this.source.GetPixelRowSpan(y); + ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - ref TPixel sourcePixel = ref row[x]; + ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, x); TPixel dithered = this.dither.Dither(sourcePixel, x, y, this.bitDepth, this.scale); - sourcePixel = Unsafe.AsRef(this.processor).GetPaletteColor(dithered, paletteSpan); + sourcePixel = Unsafe.AsRef(this.processor).GetPaletteColor(dithered); } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 4d4ccf1ab4..6b5ffabf49 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -4,6 +4,7 @@ using System; using System.Buffers; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -39,6 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering this.ditherProcessor = new DitherProcessor( this.Configuration, + Rectangle.Intersect(this.SourceRectangle, source.Bounds()), this.paletteMemory.Memory, definition.DitherScale); } @@ -71,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// Used to allow inlining of calls to - /// . + /// . /// private readonly struct DitherProcessor : IPaletteDitherImageProcessor { @@ -80,11 +82,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering [MethodImpl(InliningOptions.ShortMethod)] public DitherProcessor( Configuration configuration, + Rectangle bounds, ReadOnlyMemory palette, float ditherScale) { this.Configuration = configuration; - this.pixelMap = new EuclideanPixelMap(configuration, palette); + this.pixelMap = new EuclideanPixelMap(configuration, palette, palette.Span.Length); this.Palette = palette; this.DitherScale = ditherScale; } @@ -96,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public float DitherScale { get; } [MethodImpl(InliningOptions.ShortMethod)] - public TPixel GetPaletteColor(TPixel color, ReadOnlySpan palette) + public TPixel GetPaletteColor(TPixel color) { this.pixelMap.GetClosestColor(color, out TPixel match); return match; diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 7147886297..6c23ba356f 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -2,88 +2,86 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Collections.Concurrent; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// /// Gets the closest color to the supplied color based upon the Euclidean distance. - /// TODO: Expose this somehow. /// /// The pixel format. - internal readonly struct EuclideanPixelMap : IPixelMap, IEquatable> + internal readonly struct EuclideanPixelMap where TPixel : unmanaged, IPixel { private readonly Vector4[] vectorCache; private readonly ConcurrentDictionary distanceCache; + private readonly ReadOnlyMemory palette; + private readonly int length; /// /// Initializes a new instance of the struct. /// /// The configuration. /// The color palette to map from. + /// The length of the color palette. [MethodImpl(InliningOptions.ShortMethod)] - public EuclideanPixelMap(Configuration configuration, ReadOnlyMemory palette) + public EuclideanPixelMap(Configuration configuration, ReadOnlyMemory palette, int length) { - Guard.MustBeGreaterThan(palette.Length, 0, nameof(palette)); - - this.Palette = palette; - ReadOnlySpan paletteSpan = this.Palette.Span; - this.vectorCache = new Vector4[paletteSpan.Length]; - this.distanceCache = new ConcurrentDictionary(); + this.palette = palette; + this.length = length; + ReadOnlySpan paletteSpan = this.palette.Span.Slice(0, this.length); + this.vectorCache = new Vector4[length]; + // Use the same rules across all target frameworks. + this.distanceCache = new ConcurrentDictionary(Environment.ProcessorCount, 31); PixelOperations.Instance.ToVector4(configuration, paletteSpan, this.vectorCache); } - /// - public ReadOnlyMemory Palette - { - [MethodImpl(InliningOptions.ShortMethod)] - get; - } - - /// - public override bool Equals(object obj) - => obj is EuclideanPixelMap map && this.Equals(map); - - /// - public bool Equals(EuclideanPixelMap other) - => this.Palette.Equals(other.Palette); + /// + /// Returns the palette span. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public ReadOnlySpan GetPaletteSpan() => this.palette.Span.Slice(0, this.length); - /// + /// + /// Returns the closest color in the palette and the index of that pixel. + /// The palette contents must match the one used in the constructor. + /// + /// The color to match. + /// The matched color. + /// The index. [MethodImpl(InliningOptions.ShortMethod)] public int GetClosestColor(TPixel color, out TPixel match) { - ReadOnlySpan paletteSpan = this.Palette.Span; + ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.GetPaletteSpan()); // Check if the color is in the lookup table if (!this.distanceCache.TryGetValue(color, out int index)) { - return this.GetClosestColorSlow(color, paletteSpan, out match); + return this.GetClosestColorSlow(color, ref paletteRef, out match); } - match = paletteSpan[index]; + match = Unsafe.Add(ref paletteRef, index); return index; } - /// - public override int GetHashCode() => this.vectorCache.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private int GetClosestColorSlow(TPixel color, ReadOnlySpan palette, out TPixel match) + private int GetClosestColorSlow(TPixel color, ref TPixel paletteRef, out TPixel match) { // Loop through the palette and find the nearest match. int index = 0; float leastDistance = float.MaxValue; - Vector4 vector = color.ToScaledVector4(); - ref TPixel paletteRef = ref MemoryMarshal.GetReference(palette); + var vector = color.ToVector4(); ref Vector4 vectorCacheRef = ref MemoryMarshal.GetReference(this.vectorCache); - for (int i = 0; i < palette.Length; i++) + for (int i = 0; i < this.length; i++) { Vector4 candidate = Unsafe.Add(ref vectorCacheRef, i); float distance = Vector4.DistanceSquared(vector, candidate); @@ -108,5 +106,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization match = Unsafe.Add(ref paletteRef, index); return index; } - } + } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs index ef97f57e3d..f695a705eb 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -40,20 +41,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ReadOnlySpan palette = quantizer.BuildPalette(source, interest); MemoryAllocator memoryAllocator = quantizer.Configuration.MemoryAllocator; - var quantizedFrame = new QuantizedFrame(memoryAllocator, interest.Width, interest.Height, palette); + var destination = new QuantizedFrame(memoryAllocator, interest.Width, interest.Height, palette); if (quantizer.Options.Dither is null) { - SecondPass(ref quantizer, source, quantizedFrame, interest); + SecondPass(ref quantizer, source, destination, interest); } else { // We clone the image as we don't want to alter the original via error diffusion based dithering. using ImageFrame clone = source.Clone(); - SecondPass(ref quantizer, clone, quantizedFrame, interest); + SecondPass(ref quantizer, clone, destination, interest); } - return quantizedFrame; + return destination; } [MethodImpl(InliningOptions.ShortMethod)] @@ -106,7 +107,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { - ReadOnlySpan paletteSpan = this.destination.Palette; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - destinationRow[x - offsetX] = Unsafe.AsRef(this.quantizer).GetQuantizedColor(sourceRow[x], paletteSpan, out TPixel _); + destinationRow[x - offsetX] = Unsafe.AsRef(this.quantizer).GetQuantizedColor(sourceRow[x], out TPixel _); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index 506767277d..d49852cf13 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -45,10 +45,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Returns the index and color from the quantized palette corresponding to the given color. /// /// The color to match. - /// The output color palette. /// The matched color. /// The index. - byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match); + byte GetQuantizedColor(TPixel color, out TPixel match); // TODO: Enable bulk operations. // void GetQuantizedColors(ReadOnlySpan colors, ReadOnlySpan palette, Span indices, Span matches); diff --git a/src/ImageSharp/Processing/Processors/Quantization/IPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IPixelMap{TPixel}.cs deleted file mode 100644 index b421dce218..0000000000 --- a/src/ImageSharp/Processing/Processors/Quantization/IPixelMap{TPixel}.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Processing.Processors.Quantization -{ - /// - /// Allows the mapping of input colors to colors within a given palette. - /// TODO: Expose this somehow. - /// - /// The pixel format. - internal interface IPixelMap - where TPixel : unmanaged, IPixel - { - /// - /// Gets the color palette containing colors to match. - /// - ReadOnlyMemory Palette { get; } - - /// - /// Returns the closest color in the palette and the index of that pixel. - /// - /// The color to match. - /// The matched color. - /// The index. - int GetClosestColor(TPixel color, out TPixel match); - } -} diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index e80449b09f..cc6a3a4859 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -82,29 +83,32 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } Span paletteSpan = this.palette.GetSpan(); - this.octree.Palletize(paletteSpan, this.colors); + int paletteIndex = 0; + this.octree.Palletize(paletteSpan, this.colors, ref paletteIndex); - // TODO: Cannot make method readonly due to this line. - this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory); + // Length of reduced palette + transparency. + paletteSpan = paletteSpan.Slice(0, Math.Min(paletteIndex + 2, QuantizerConstants.MaxColors)); + this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory, paletteSpan.Length); return paletteSpan; } /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) + public readonly byte GetQuantizedColor(TPixel color, out TPixel match) { // Octree only maps the RGB component of a color // so cannot tell the difference between a fully transparent // pixel and a black one. - if (!this.isDithering && !color.Equals(default)) + if (this.isDithering || color.Equals(default)) { - var index = (byte)this.octree.GetPaletteIndex(color); - match = palette[index]; - return index; + return (byte)this.pixelMap.GetClosestColor(color, out match); } - return (byte)this.pixelMap.GetClosestColor(color, out match); + ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.pixelMap.GetPaletteSpan()); + var index = (byte)this.octree.GetPaletteIndex(color); + match = Unsafe.Add(ref paletteRef, index); + return index; } /// @@ -223,15 +227,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The palette to fill. /// The maximum number of colors + /// The palette index, used to calculate the final size of the palette. [MethodImpl(InliningOptions.ShortMethod)] - public void Palletize(Span palette, int colorCount) + public void Palletize(Span palette, int colorCount, ref int paletteIndex) { while (this.Leaves > colorCount - 1) { this.Reduce(); } - int paletteIndex = 0; this.root.ConstructPalette(palette, ref paletteIndex); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index 3dbf77a3a9..11570beef3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -4,6 +4,7 @@ using System; using System.Buffers; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -17,54 +18,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization internal struct PaletteFrameQuantizer : IFrameQuantizer where TPixel : unmanaged, IPixel { - private IMemoryOwner paletteOwner; private readonly EuclideanPixelMap pixelMap; - private bool isDisposed; /// /// Initializes a new instance of the struct. /// /// The configuration which allows altering default behaviour or extending the library. /// The quantizer options defining quantization rules. - /// A containing all colors in the palette. + /// The pixel map for looking up color matches from a predefined palette. [MethodImpl(InliningOptions.ShortMethod)] - public PaletteFrameQuantizer(Configuration configuration, QuantizerOptions options, ReadOnlySpan colors) + public PaletteFrameQuantizer( + Configuration configuration, + QuantizerOptions options, + EuclideanPixelMap pixelMap) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(options, nameof(options)); this.Configuration = configuration; this.Options = options; - - int maxLength = Math.Min(colors.Length, options.MaxColors); - this.paletteOwner = configuration.MemoryAllocator.Allocate(maxLength); - Color.ToPixel(configuration, colors, this.paletteOwner.GetSpan()); - - this.pixelMap = new EuclideanPixelMap(configuration, this.paletteOwner.Memory); - this.isDisposed = false; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The configuration which allows altering default behaviour or extending the library. - /// The quantizer options defining quantization rules. - /// A containing all colors in the palette. - [MethodImpl(InliningOptions.ShortMethod)] - public PaletteFrameQuantizer(Configuration configuration, QuantizerOptions options, ReadOnlySpan palette) - { - Guard.NotNull(configuration, nameof(configuration)); - Guard.NotNull(options, nameof(options)); - - this.Configuration = configuration; - this.Options = options; - - int maxLength = Math.Min(palette.Length, options.MaxColors); - this.paletteOwner = configuration.MemoryAllocator.Allocate(maxLength); - palette.CopyTo(this.paletteOwner.GetSpan()); - - this.pixelMap = new EuclideanPixelMap(configuration, this.paletteOwner.Memory); - this.isDisposed = false; + this.pixelMap = pixelMap; } /// @@ -81,24 +54,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] public readonly ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds) - => this.paletteOwner.GetSpan(); + => this.pixelMap.GetPaletteSpan(); /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) + public readonly byte GetQuantizedColor(TPixel color, out TPixel match) => (byte)this.pixelMap.GetClosestColor(color, out match); /// public void Dispose() { - if (this.isDisposed) - { - return; - } - - this.isDisposed = true; - this.paletteOwner.Dispose(); - this.paletteOwner = null; } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index e95f8c5db5..7bae8787bb 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public class PaletteQuantizer : IQuantizer { private static readonly QuantizerOptions DefaultOptions = new QuantizerOptions(); - private readonly ReadOnlyMemory palette; + private readonly ReadOnlyMemory colorPalette; /// /// Initializes a new instance of the class. @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.MustBeGreaterThan(palette.Length, 0, nameof(palette)); Guard.NotNull(options, nameof(options)); - this.palette = palette; + this.colorPalette = palette; this.Options = options; } @@ -50,7 +50,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization where TPixel : unmanaged, IPixel { Guard.NotNull(options, nameof(options)); - return new PaletteFrameQuantizer(configuration, options, this.palette.Span); + + // The palette quantizer can reuse the same pixel map across multiple frames + // since the palette is unchanging. This allows a reduction of memory usage across + // multi frame gifs using a global palette. + int length = Math.Min(this.colorPalette.Length, options.MaxColors); + var palette = new TPixel[length]; + Color.ToPixel(configuration, this.colorPalette.Span, palette.AsSpan()); + var pixelMap = new EuclideanPixelMap(configuration, palette, length); + return new PaletteFrameQuantizer(configuration, options, pixelMap); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index 04586807e7..5a0116a03f 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public void Invoke(in RowInterval rows) { ReadOnlySpan quantizedPixelSpan = this.quantized.GetPixelSpan(); - ReadOnlySpan paletteSpan = this.quantized.Palette; + ReadOnlySpan paletteSpan = this.quantized.Palette.Span; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; int width = this.bounds.Width; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index cda0546e4a..d5facbe63a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -53,10 +53,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Gets the color palette of this . /// - public ReadOnlySpan Palette + public ReadOnlyMemory Palette { [MethodImpl(InliningOptions.ShortMethod)] - get { return this.palette.GetSpan(); } + get { return this.palette.Memory; } } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 6f98ce121e..f50282f9a8 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -131,13 +132,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - // TODO: Cannot make methods readonly due to this line. - this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory); + paletteSpan = paletteSpan.Slice(0, this.colors); + this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory, paletteSpan.Length); return paletteSpan; } /// - public readonly byte GetQuantizedColor(TPixel color, ReadOnlySpan palette, out TPixel match) + public readonly byte GetQuantizedColor(TPixel color, out TPixel match) { if (this.isDithering) { @@ -154,7 +155,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ReadOnlySpan tagSpan = this.tag.GetSpan(); byte index = tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)]; - match = palette[index]; + ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.pixelMap.GetPaletteSpan()); + match = Unsafe.Add(ref paletteRef, index); return index; } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 588f652548..4adffca4ff 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -5,6 +5,7 @@ using System.IO; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; @@ -25,6 +26,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif { TestImages.Gif.Ratio4x1, 4, 1, PixelResolutionUnit.AspectRatio } }; + [Theory] + [WithFile(TestImages.Bmp.Car, PixelTypes.Rgba32)] + public void EncodeAllocationCheck(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + GifEncoder encoder = new GifEncoder + { + Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 }) + }; + + using (Image image = provider.GetImage()) + { + // Always save as we need to compare the encoded output. + provider.Utility.SaveTestOutputFile(image, "gif", encoder); + } + } + [Theory] [WithTestPatternImages(100, 100, TestPixelTypes, false)] [WithTestPatternImages(100, 100, TestPixelTypes, false)] diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 4085d99439..cd93ab0cf8 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests // Transparent pixels are much more likely to be found at the end of a palette int index = -1; Rgba32 trans = default; - ReadOnlySpan paletteSpan = quantized.Palette; + ReadOnlySpan paletteSpan = quantized.Palette.Span; for (int i = paletteSpan.Length - 1; i >= 0; i--) { paletteSpan[i].ToRgba32(ref trans); diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index 34888f1dbc..f3bcd0b955 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); - Assert.Equal(Color.Black, (Color)result.Palette[0]); + Assert.Equal(Color.Black, (Color)result.Palette.Span[0]); Assert.Equal(0, result.GetPixelSpan()[0]); } @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); - Assert.Equal(default, result.Palette[0]); + Assert.Equal(default, result.Palette.Span[0]); Assert.Equal(0, result.GetPixelSpan()[0]); } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization var actualImage = new Image(1, 256); - ReadOnlySpan paletteSpan = result.Palette; + ReadOnlySpan paletteSpan = result.Palette.Span; int paletteCount = result.Palette.Length - 1; for (int y = 0; y < actualImage.Height; y++) { @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(4 * 8, result.Palette.Length); Assert.Equal(256, result.GetPixelSpan().Length); - ReadOnlySpan paletteSpan = result.Palette; + ReadOnlySpan paletteSpan = result.Palette.Span; int paletteCount = result.Palette.Length - 1; for (int y = 0; y < actualImage.Height; y++) { From d9596ef33b213fd65210e2c6789be3d61188d2c0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 4 Mar 2020 00:25:22 +1100 Subject: [PATCH 038/213] Cleanup and update references. --- .../Processors/Quantization/EuclideanPixelMap{TPixel}.cs | 4 +--- .../Processors/Quantization/FrameQuantizerExtensions.cs | 1 - .../Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs | 3 --- .../Processing/Processors/Quantization/PaletteQuantizer.cs | 2 ++ tests/Images/External | 2 +- 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 6c23ba356f..84a204bba7 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -2,12 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Collections.Concurrent; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Quantization @@ -106,5 +104,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization match = Unsafe.Add(ref paletteRef, index); return index; } - } + } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs index f695a705eb..139ed6e9ea 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index 11570beef3..a9a9385626 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -2,10 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Quantization diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 7bae8787bb..e856c389c4 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -56,7 +56,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // multi frame gifs using a global palette. int length = Math.Min(this.colorPalette.Length, options.MaxColors); var palette = new TPixel[length]; + Color.ToPixel(configuration, this.colorPalette.Span, palette.AsSpan()); + var pixelMap = new EuclideanPixelMap(configuration, palette, length); return new PaletteFrameQuantizer(configuration, options, pixelMap); } diff --git a/tests/Images/External b/tests/Images/External index f8a76fd3a9..1fea1ceab8 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit f8a76fd3a900b90c98df67ac896574383a4d09f3 +Subproject commit 1fea1ceab89e87cc5f11376fa46164d3d27566c0 From 590777c5e1f5f0fb661d97dd70cc6f9d113479b0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 4 Mar 2020 00:51:41 +0100 Subject: [PATCH 039/213] extend EncodeGif benchmark --- tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs index 71405890cd..70c85ef022 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs @@ -27,12 +27,15 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 }) }; + [Params(TestImages.Bmp.Car, TestImages.Png.Rgb48Bpp)] + public string TestImage { get; set; } + [GlobalSetup] public void ReadImages() { if (this.bmpStream == null) { - this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Bmp.Car)); + this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage)); this.bmpCore = Image.Load(this.bmpStream); this.bmpStream.Position = 0; this.bmpDrawing = SDImage.FromStream(this.bmpStream); From f0d55caf17737f94f80a7df3e032848b80442431 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 4 Mar 2020 01:34:27 +0100 Subject: [PATCH 040/213] Revert "Merge branch 'af/fast-dev-hack' into js/dither-quantize-updates" This reverts commit 87327172656a9898690ca3e91a0907d8799b7900, reversing changes made to d9596ef33b213fd65210e2c6789be3d61188d2c0. --- src/ImageSharp/ImageSharp.csproj | 3 +-- tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 3 +-- .../ImageSharp.Tests.ProfilingSandbox.csproj | 3 +-- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 0d803475a4..be0e9032b6 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -10,8 +10,7 @@ $(packageversion) 0.0.1 - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 true true diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 101d279569..f380d0a6a9 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -5,8 +5,7 @@ ImageSharp.Benchmarks Exe SixLabors.ImageSharp.Benchmarks - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 false false diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index f9e6c9da59..7c80316930 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -8,8 +8,7 @@ false SixLabors.ImageSharp.Tests.ProfilingSandbox win7-x64 - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 SixLabors.ImageSharp.Tests.ProfilingSandbox.Program false diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index d5c8ef16ee..fdb280ca99 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,8 +2,7 @@ - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 True True SixLabors.ImageSharp.Tests From 1837f6abb9f7eb23dc5322587f4e1e54627f33e9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 5 Mar 2020 15:16:20 +1100 Subject: [PATCH 041/213] Clean up quantized frame API --- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 25 ++-- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 22 ++-- .../Formats/Png/PngEncoderOptionsHelpers.cs | 4 +- .../ArrayPoolMemoryAllocator.Buffer{T}.cs | 2 +- .../Processors/Dithering/ErrorDither.cs | 4 +- .../Processors/Dithering/IDither.cs | 2 +- .../Processors/Dithering/OrderedDither.cs | 57 ++++----- .../PaletteDitherProcessor{TPixel}.cs | 4 +- .../Quantization/EuclideanPixelMap{TPixel}.cs | 29 ++--- .../Quantization/FrameQuantizerExtensions.cs | 18 ++- .../Quantization/IFrameQuantizer{TPixel}.cs | 20 +-- .../Quantization/IndexedImageFrame{TPixel}.cs | 115 ++++++++++++++++++ .../OctreeFrameQuantizer{TPixel}.cs | 30 ++--- .../PaletteFrameQuantizer{TPixel}.cs | 6 +- .../Quantization/PaletteQuantizer.cs | 2 +- .../Quantization/QuantizeProcessor{TPixel}.cs | 8 +- .../Quantization/QuantizedFrame{TPixel}.cs | 94 -------------- .../Quantization/WuFrameQuantizer{TPixel}.cs | 68 +++++------ .../Quantization/QuantizedImageTests.cs | 20 +-- .../Quantization/WuQuantizerTests.cs | 30 ++--- 21 files changed, 285 insertions(+), 277 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs delete mode 100644 src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 3d5854ce57..7d27995038 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -337,7 +337,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp where TPixel : unmanaged, IPixel { using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration); - using QuantizedFrame quantized = frameQuantizer.QuantizeFrame(image, image.Bounds()); + using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(image, image.Bounds()); ReadOnlySpan quantizedColors = quantized.Palette.Span; var color = default(Rgba32); diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index dc74353e39..29e2e8fe2e 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Gif bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; // Quantize the image returning a palette. - QuantizedFrame quantized; + IndexedImageFrame quantized; using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration)) { quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.Formats.Gif stream.WriteByte(GifConstants.EndIntroducer); } - private void EncodeGlobal(Image image, QuantizedFrame quantized, int transparencyIndex, Stream stream) + private void EncodeGlobal(Image image, IndexedImageFrame quantized, int transparencyIndex, Stream stream) where TPixel : unmanaged, IPixel { // The palette quantizer can reuse the same pixel map across multiple frames @@ -150,17 +150,17 @@ namespace SixLabors.ImageSharp.Formats.Gif if (!pixelMapSet) { pixelMapSet = true; - pixelMap = new EuclideanPixelMap(this.configuration, quantized.Palette, quantized.Palette.Span.Length); + pixelMap = new EuclideanPixelMap(this.configuration, quantized.Palette); } using var paletteFrameQuantizer = new PaletteFrameQuantizer(this.configuration, this.quantizer.Options, pixelMap); - using QuantizedFrame paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds()); this.WriteImageData(paletteQuantized, stream); } } } - private void EncodeLocal(Image image, QuantizedFrame quantized, Stream stream) + private void EncodeLocal(Image image, IndexedImageFrame quantized, Stream stream) where TPixel : unmanaged, IPixel { ImageFrame previousFrame = null; @@ -214,10 +214,10 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The . /// - private int GetTransparentIndex(QuantizedFrame quantized) + private int GetTransparentIndex(IndexedImageFrame quantized) where TPixel : unmanaged, IPixel { - // Transparent pixels are much more likely to be found at the end of a palette + // Transparent pixels are much more likely to be found at the end of a palette. int index = -1; int length = quantized.Palette.Length; @@ -447,19 +447,20 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The pixel format. /// The to encode. /// The stream to write to. - private void WriteColorTable(QuantizedFrame image, Stream stream) + private void WriteColorTable(IndexedImageFrame image, Stream stream) where TPixel : unmanaged, IPixel { // The maximum number of colors for the bit depth int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; int pixelCount = image.Palette.Length; - using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength); + using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength, AllocationOptions.Clean); PixelOperations.Instance.ToRgb24Bytes( this.configuration, image.Palette.Span, colorTable.GetSpan(), pixelCount); + stream.Write(colorTable.Array, 0, colorTableLength); } @@ -467,13 +468,13 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Writes the image pixel data to the stream. /// /// The pixel format. - /// The containing indexed pixels. + /// The containing indexed pixels. /// The stream to write to. - private void WriteImageData(QuantizedFrame image, Stream stream) + private void WriteImageData(IndexedImageFrame image, Stream stream) where TPixel : unmanaged, IPixel { using var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth); - encoder.Encode(image.GetPixelSpan(), stream); + encoder.Encode(image.GetPixelBufferSpan(), stream); } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index ce624f768a..6caaa1df02 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.Formats.Png ImageMetadata metadata = image.Metadata; PngMetadata pngMetadata = metadata.GetPngMetadata(); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); - QuantizedFrame quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, image); + IndexedImageFrame quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, image); this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, image, quantized); stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); @@ -371,7 +371,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The row span. /// The quantized pixels. Can be null. /// The row. - private void CollectPixelBytes(ReadOnlySpan rowSpan, QuantizedFrame quantized, int row) + private void CollectPixelBytes(ReadOnlySpan rowSpan, IndexedImageFrame quantized, int row) where TPixel : unmanaged, IPixel { switch (this.options.ColorType) @@ -385,7 +385,7 @@ namespace SixLabors.ImageSharp.Formats.Png else { int stride = this.currentScanline.Length(); - quantized.GetPixelSpan().Slice(row * stride, stride).CopyTo(this.currentScanline.GetSpan()); + quantized.GetPixelBufferSpan().Slice(row * stride, stride).CopyTo(this.currentScanline.GetSpan()); } break; @@ -440,7 +440,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The quantized pixels. Can be null. /// The row. /// The - private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, QuantizedFrame quantized, int row) + private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, IndexedImageFrame quantized, int row) where TPixel : unmanaged, IPixel { this.CollectPixelBytes(rowSpan, quantized, row); @@ -546,17 +546,17 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing image data. /// The quantized frame. - private void WritePaletteChunk(Stream stream, QuantizedFrame quantized) + private void WritePaletteChunk(Stream stream, IndexedImageFrame quantized) where TPixel : unmanaged, IPixel { - if (quantized == null) + if (quantized is null) { return; } // Grab the palette and write it to the stream. ReadOnlySpan palette = quantized.Palette.Span; - int paletteLength = Math.Min(palette.Length, 256); + int paletteLength = Math.Min(palette.Length, QuantizerConstants.MaxColors); int colorTableLength = paletteLength * 3; bool anyAlpha = false; @@ -565,7 +565,7 @@ namespace SixLabors.ImageSharp.Formats.Png { ref byte colorTableRef = ref MemoryMarshal.GetReference(colorTable.GetSpan()); ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); - ReadOnlySpan quantizedSpan = quantized.GetPixelSpan(); + ReadOnlySpan quantizedSpan = quantized.GetPixelBufferSpan(); Rgba32 rgba = default; @@ -783,7 +783,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image. /// The quantized pixel data. Can be null. /// The stream. - private void WriteDataChunks(ImageFrame pixels, QuantizedFrame quantized, Stream stream) + private void WriteDataChunks(ImageFrame pixels, IndexedImageFrame quantized, Stream stream) where TPixel : unmanaged, IPixel { byte[] buffer; @@ -881,7 +881,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixels. /// The quantized pixels span. /// The deflate stream. - private void EncodePixels(ImageFrame pixels, QuantizedFrame quantized, ZlibDeflateStream deflateStream) + private void EncodePixels(ImageFrame pixels, IndexedImageFrame quantized, ZlibDeflateStream deflateStream) where TPixel : unmanaged, IPixel { int bytesPerScanline = this.CalculateScanlineLength(this.width); @@ -960,7 +960,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The type of the pixel. /// The quantized. /// The deflate stream. - private void EncodeAdam7IndexedPixels(QuantizedFrame quantized, ZlibDeflateStream deflateStream) + private void EncodeAdam7IndexedPixels(IndexedImageFrame quantized, ZlibDeflateStream deflateStream) where TPixel : unmanaged, IPixel { int width = quantized.Width; diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs index 20b8c41c9f..3f490ca6f8 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The type of the pixel. /// The options. /// The image. - public static QuantizedFrame CreateQuantizedFrame( + public static IndexedImageFrame CreateQuantizedFrame( PngEncoderOptions options, Image image) where TPixel : unmanaged, IPixel @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Formats.Png public static byte CalculateBitDepth( PngEncoderOptions options, Image image, - QuantizedFrame quantizedFrame) + IndexedImageFrame quantizedFrame) where TPixel : unmanaged, IPixel { byte bitDepth; diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs index 7a8b4f8bd7..16ca4de678 100644 --- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Memory /// public override Span GetSpan() { - if (this.Data == null) + if (this.Data is null) { throw new ObjectDisposedException("ArrayPoolMemoryAllocator.Buffer"); } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 9d0c563da4..7d30bada6e 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public void ApplyQuantizationDither( ref TFrameQuantizer quantizer, ImageFrame source, - QuantizedFrame destination, + IndexedImageFrame destination, Rectangle bounds) where TFrameQuantizer : struct, IFrameQuantizer where TPixel : unmanaged, IPixel @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering for (int y = bounds.Top; y < bounds.Bottom; y++) { ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(source.GetPixelRowSpan(y)); - ref byte destinationRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y - offsetY)); + ref byte destinationRowRef = ref MemoryMarshal.GetReference(destination.GetWritablePixelRowSpanUnsafe(y - offsetY)); for (int x = bounds.Left; x < bounds.Right; x++) { diff --git a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs index f7057b8f3e..8f9d82537b 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering void ApplyQuantizationDither( ref TFrameQuantizer quantizer, ImageFrame source, - QuantizedFrame destination, + IndexedImageFrame destination, Rectangle bounds) where TFrameQuantizer : struct, IFrameQuantizer where TPixel : unmanaged, IPixel; diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 3e25e2a02a..6862cff000 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -5,7 +5,6 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -107,19 +106,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public void ApplyQuantizationDither( ref TFrameQuantizer quantizer, ImageFrame source, - QuantizedFrame destination, + IndexedImageFrame destination, Rectangle bounds) where TFrameQuantizer : struct, IFrameQuantizer where TPixel : unmanaged, IPixel { - var ditherOperation = new QuantizeDitherRowIntervalOperation( + var ditherOperation = new QuantizeDitherRowOperation( ref quantizer, in Unsafe.AsRef(this), source, destination, bounds); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( quantizer.Configuration, bounds, in ditherOperation); @@ -134,13 +133,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor where TPixel : unmanaged, IPixel { - var ditherOperation = new PaletteDitherRowIntervalOperation( + var ditherOperation = new PaletteDitherRowOperation( in processor, in Unsafe.AsRef(this), source, bounds); - ParallelRowIterator.IterateRowIntervals( + ParallelRowIterator.IterateRows( processor.Configuration, bounds, in ditherOperation); @@ -195,23 +194,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public override int GetHashCode() => HashCode.Combine(this.thresholdMatrix, this.modulusX, this.modulusY); - private readonly struct QuantizeDitherRowIntervalOperation : IRowIntervalOperation + private readonly struct QuantizeDitherRowOperation : IRowOperation where TFrameQuantizer : struct, IFrameQuantizer where TPixel : unmanaged, IPixel { private readonly TFrameQuantizer quantizer; private readonly OrderedDither dither; private readonly ImageFrame source; - private readonly QuantizedFrame destination; + private readonly IndexedImageFrame destination; private readonly Rectangle bounds; private readonly int bitDepth; [MethodImpl(InliningOptions.ShortMethod)] - public QuantizeDitherRowIntervalOperation( + public QuantizeDitherRowOperation( ref TFrameQuantizer quantizer, in OrderedDither dither, ImageFrame source, - QuantizedFrame destination, + IndexedImageFrame destination, Rectangle bounds) { this.quantizer = quantizer; @@ -223,27 +222,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; float scale = this.quantizer.Options.DitherScale; - for (int y = rows.Min; y < rows.Max; y++) + ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); + ref byte destinationRowRef = ref MemoryMarshal.GetReference(this.destination.GetWritablePixelRowSpanUnsafe(y - offsetY)); + + for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); - ref byte destinationRowRef = ref MemoryMarshal.GetReference(this.destination.GetPixelRowSpan(y - offsetY)); - - for (int x = this.bounds.Left; x < this.bounds.Right; x++) - { - TPixel dithered = this.dither.Dither(Unsafe.Add(ref sourceRowRef, x), x, y, this.bitDepth, scale); - Unsafe.Add(ref destinationRowRef, x - offsetX) = Unsafe.AsRef(this.quantizer).GetQuantizedColor(dithered, out TPixel _); - } + TPixel dithered = this.dither.Dither(Unsafe.Add(ref sourceRowRef, x), x, y, this.bitDepth, scale); + Unsafe.Add(ref destinationRowRef, x - offsetX) = Unsafe.AsRef(this.quantizer).GetQuantizedColor(dithered, out TPixel _); } } } - private readonly struct PaletteDitherRowIntervalOperation : IRowIntervalOperation + private readonly struct PaletteDitherRowOperation : IRowOperation where TPaletteDitherImageProcessor : struct, IPaletteDitherImageProcessor where TPixel : unmanaged, IPixel { @@ -255,7 +251,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering private readonly int bitDepth; [MethodImpl(InliningOptions.ShortMethod)] - public PaletteDitherRowIntervalOperation( + public PaletteDitherRowOperation( in TPaletteDitherImageProcessor processor, in OrderedDither dither, ImageFrame source, @@ -270,18 +266,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) + ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); + + for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); - - for (int x = this.bounds.Left; x < this.bounds.Right; x++) - { - ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, x); - TPixel dithered = this.dither.Dither(sourcePixel, x, y, this.bitDepth, this.scale); - sourcePixel = Unsafe.AsRef(this.processor).GetPaletteColor(dithered); - } + ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, x); + TPixel dithered = this.dither.Dither(sourcePixel, x, y, this.bitDepth, this.scale); + sourcePixel = Unsafe.AsRef(this.processor).GetPaletteColor(dithered); } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 6b5ffabf49..1f554536c6 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -40,7 +40,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering this.ditherProcessor = new DitherProcessor( this.Configuration, - Rectangle.Intersect(this.SourceRectangle, source.Bounds()), this.paletteMemory.Memory, definition.DitherScale); } @@ -82,12 +81,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering [MethodImpl(InliningOptions.ShortMethod)] public DitherProcessor( Configuration configuration, - Rectangle bounds, ReadOnlyMemory palette, float ditherScale) { this.Configuration = configuration; - this.pixelMap = new EuclideanPixelMap(configuration, palette, palette.Span.Length); + this.pixelMap = new EuclideanPixelMap(configuration, palette); this.Palette = palette; this.DitherScale = ditherScale; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 84a204bba7..775e0aa23f 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -19,34 +19,32 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { private readonly Vector4[] vectorCache; private readonly ConcurrentDictionary distanceCache; - private readonly ReadOnlyMemory palette; - private readonly int length; /// /// Initializes a new instance of the struct. /// /// The configuration. /// The color palette to map from. - /// The length of the color palette. [MethodImpl(InliningOptions.ShortMethod)] - public EuclideanPixelMap(Configuration configuration, ReadOnlyMemory palette, int length) + public EuclideanPixelMap(Configuration configuration, ReadOnlyMemory palette) { - this.palette = palette; - this.length = length; - ReadOnlySpan paletteSpan = this.palette.Span.Slice(0, this.length); - this.vectorCache = new Vector4[length]; + this.Palette = palette; + this.vectorCache = new Vector4[palette.Length]; // Use the same rules across all target frameworks. this.distanceCache = new ConcurrentDictionary(Environment.ProcessorCount, 31); - PixelOperations.Instance.ToVector4(configuration, paletteSpan, this.vectorCache); + PixelOperations.Instance.ToVector4(configuration, this.Palette.Span, this.vectorCache); } /// - /// Returns the palette span. + /// Gets the color palette of this . + /// The palette memory is owned by the palette source that created it. /// - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlySpan GetPaletteSpan() => this.palette.Span.Slice(0, this.length); + public ReadOnlyMemory Palette + { + [MethodImpl(InliningOptions.ShortMethod)] + get; + } /// /// Returns the closest color in the palette and the index of that pixel. @@ -58,7 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(InliningOptions.ShortMethod)] public int GetClosestColor(TPixel color, out TPixel match) { - ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.GetPaletteSpan()); + ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.Palette.Span); // Check if the color is in the lookup table if (!this.distanceCache.TryGetValue(color, out int index)) @@ -78,8 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization float leastDistance = float.MaxValue; var vector = color.ToVector4(); ref Vector4 vectorCacheRef = ref MemoryMarshal.GetReference(this.vectorCache); - - for (int i = 0; i < this.length; i++) + for (int i = 0; i < this.Palette.Length; i++) { Vector4 candidate = Unsafe.Add(ref vectorCacheRef, i); float distance = Vector4.DistanceSquared(vector, candidate); diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs index 88973c44b4..26da6a3976 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs @@ -24,9 +24,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The source image frame to quantize. /// The bounds within the frame to quantize. /// - /// A representing a quantized version of the source frame pixels. + /// A representing a quantized version of the source frame pixels. /// - public static QuantizedFrame QuantizeFrame( + public static IndexedImageFrame QuantizeFrame( ref TFrameQuantizer quantizer, ImageFrame source, Rectangle bounds) @@ -37,10 +37,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization var interest = Rectangle.Intersect(source.Bounds(), bounds); // Collect the palette. Required before the second pass runs. - ReadOnlySpan palette = quantizer.BuildPalette(source, interest); - MemoryAllocator memoryAllocator = quantizer.Configuration.MemoryAllocator; - - var destination = new QuantizedFrame(memoryAllocator, interest.Width, interest.Height, palette); + ReadOnlyMemory palette = quantizer.BuildPalette(source, interest); + var destination = new IndexedImageFrame(quantizer.Configuration, interest.Width, interest.Height, palette); if (quantizer.Options.Dither is null) { @@ -60,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private static void SecondPass( ref TFrameQuantizer quantizer, ImageFrame source, - QuantizedFrame destination, + IndexedImageFrame destination, Rectangle bounds) where TFrameQuantizer : struct, IFrameQuantizer where TPixel : unmanaged, IPixel @@ -87,14 +85,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { private readonly TFrameQuantizer quantizer; private readonly ImageFrame source; - private readonly QuantizedFrame destination; + private readonly IndexedImageFrame destination; private readonly Rectangle bounds; [MethodImpl(InliningOptions.ShortMethod)] public RowIntervalOperation( ref TFrameQuantizer quantizer, ImageFrame source, - QuantizedFrame destination, + IndexedImageFrame destination, Rectangle bounds) { this.quantizer = quantizer; @@ -112,7 +110,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization for (int y = rows.Min; y < rows.Max; y++) { Span sourceRow = this.source.GetPixelRowSpan(y); - Span destinationRow = this.destination.GetPixelRowSpan(y - offsetY); + Span destinationRow = this.destination.GetWritablePixelRowSpanUnsafe(y - offsetY); for (int x = this.bounds.Left; x < this.bounds.Right; x++) { diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index d49852cf13..64caad3e20 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -23,23 +23,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// QuantizerOptions Options { get; } + /// + /// Builds the quantized palette from the given image frame and bounds. + /// + /// The source image frame. + /// The region of interest bounds. + /// The palette. + ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds); + /// /// Quantizes an image frame and return the resulting output pixels. /// /// The source image frame to quantize. /// The bounds within the frame to quantize. /// - /// A representing a quantized version of the source frame pixels. + /// A representing a quantized version of the source frame pixels. /// - QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds); - - /// - /// Builds the quantized palette from the given image frame and bounds. - /// - /// The source image frame. - /// The region of interest bounds. - /// The palette. - ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds); + IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds); /// /// Returns the index and color from the quantized palette corresponding to the given color. diff --git a/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs new file mode 100644 index 0000000000..42aadb5fd0 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs @@ -0,0 +1,115 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A pixel-specific image frame where each pixel buffer value represents an index in a color palette. + /// + /// The pixel format. + public sealed class IndexedImageFrame : IDisposable + where TPixel : unmanaged, IPixel + { + private IMemoryOwner pixelsOwner; + private IMemoryOwner paletteOwner; + private bool isDisposed; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The configuration which allows altering default behaviour or extending the library. + /// + /// The frame width. + /// The frame height. + /// The color palette. + internal IndexedImageFrame(Configuration configuration, int width, int height, ReadOnlyMemory palette) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.MustBeGreaterThan(width, 0, nameof(width)); + Guard.MustBeGreaterThan(height, 0, nameof(height)); + + this.Configuration = configuration; + this.Width = width; + this.Height = height; + this.pixelsOwner = configuration.MemoryAllocator.AllocateManagedByteBuffer(width * height); + + // Copy the palette over. We want the lifetime of this frame to be independant of any palette source. + this.paletteOwner = configuration.MemoryAllocator.Allocate(palette.Length); + palette.Span.CopyTo(this.paletteOwner.GetSpan()); + this.Palette = this.paletteOwner.Memory.Slice(0, palette.Length); + } + + /// + /// Gets the configuration which allows altering default behaviour or extending the library. + /// + public Configuration Configuration { get; } + + /// + /// Gets the width of this . + /// + public int Width { get; } + + /// + /// Gets the height of this . + /// + public int Height { get; } + + /// + /// Gets the color palette of this . + /// + public ReadOnlyMemory Palette { get; } + + /// + /// Gets the pixels of this . + /// + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public ReadOnlySpan GetPixelBufferSpan() => this.pixelsOwner.GetSpan(); // TODO: Buffer2D + + /// + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the the first pixel on that row. + /// + /// The row index in the pixel buffer. + /// The pixel row as a . + [MethodImpl(InliningOptions.ShortMethod)] + public ReadOnlySpan GetPixelRowSpan(int rowIndex) + => this.GetWritablePixelRowSpanUnsafe(rowIndex); + + /// + /// + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the the first pixel on that row. + /// + /// + /// Note: Values written to this span are not sanitized against the palette length. + /// Care should be taken during assignment to prevent out-of-bounds errors. + /// + /// + /// The row index in the pixel buffer. + /// The pixel row as a . + [MethodImpl(InliningOptions.ShortMethod)] + public Span GetWritablePixelRowSpanUnsafe(int rowIndex) + => this.pixelsOwner.GetSpan().Slice(rowIndex * this.Width, this.Width); + + /// + public void Dispose() + { + if (!this.isDisposed) + { + this.isDisposed = true; + this.pixelsOwner.Dispose(); + this.paletteOwner.Dispose(); + this.pixelsOwner = null; + this.paletteOwner = null; + } + } + } +} diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index cc6a3a4859..6c31fca7fe 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -20,9 +20,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public struct OctreeFrameQuantizer : IFrameQuantizer where TPixel : unmanaged, IPixel { - private readonly int colors; + private readonly int maxColors; private readonly Octree octree; - private IMemoryOwner palette; + private IMemoryOwner paletteOwner; private EuclideanPixelMap pixelMap; private readonly bool isDithering; private bool isDisposed; @@ -41,9 +41,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.Configuration = configuration; this.Options = options; - this.colors = this.Options.MaxColors; - this.octree = new Octree(ImageMaths.GetBitsNeededForColorDepth(this.colors).Clamp(1, 8)); - this.palette = configuration.MemoryAllocator.Allocate(this.colors, AllocationOptions.Clean); + this.maxColors = this.Options.MaxColors; + this.octree = new Octree(ImageMaths.GetBitsNeededForColorDepth(this.maxColors).Clamp(1, 8)); + this.paletteOwner = configuration.MemoryAllocator.Allocate(this.maxColors, AllocationOptions.Clean); this.pixelMap = default; this.isDithering = !(this.Options.Dither is null); this.isDisposed = false; @@ -57,12 +57,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds) + public ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) { using IMemoryOwner buffer = this.Configuration.MemoryAllocator.Allocate(bounds.Width); Span bufferSpan = buffer.GetSpan(); @@ -82,15 +82,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - Span paletteSpan = this.palette.GetSpan(); + Span paletteSpan = this.paletteOwner.GetSpan(); int paletteIndex = 0; - this.octree.Palletize(paletteSpan, this.colors, ref paletteIndex); + this.octree.Palletize(paletteSpan, this.maxColors, ref paletteIndex); // Length of reduced palette + transparency. - paletteSpan = paletteSpan.Slice(0, Math.Min(paletteIndex + 2, QuantizerConstants.MaxColors)); - this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory, paletteSpan.Length); + ReadOnlyMemory result = this.paletteOwner.Memory.Slice(0, Math.Min(paletteIndex + 2, QuantizerConstants.MaxColors)); + this.pixelMap = new EuclideanPixelMap(this.Configuration, result); - return paletteSpan; + return result; } /// @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return (byte)this.pixelMap.GetClosestColor(color, out match); } - ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.pixelMap.GetPaletteSpan()); + ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.pixelMap.Palette.Span); var index = (byte)this.octree.GetPaletteIndex(color); match = Unsafe.Add(ref paletteRef, index); return index; @@ -117,8 +117,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!this.isDisposed) { this.isDisposed = true; - this.palette.Dispose(); - this.palette = null; + this.paletteOwner.Dispose(); + this.paletteOwner = null; } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index a9a9385626..d371168554 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -45,13 +45,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds) - => this.pixelMap.GetPaletteSpan(); + public readonly ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) + => this.pixelMap.Palette; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index e856c389c4..c14ea6153f 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Color.ToPixel(configuration, this.colorPalette.Span, palette.AsSpan()); - var pixelMap = new EuclideanPixelMap(configuration, palette, length); + var pixelMap = new EuclideanPixelMap(configuration, palette); return new PaletteFrameQuantizer(configuration, options, pixelMap); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index cbef193005..4583b7cff4 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Configuration configuration = this.Configuration; using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(configuration); - using QuantizedFrame quantized = frameQuantizer.QuantizeFrame(source, interest); + using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(source, interest); var operation = new RowIntervalOperation(this.SourceRectangle, source, quantized); ParallelRowIterator.IterateRowIntervals( @@ -52,13 +52,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { private readonly Rectangle bounds; private readonly ImageFrame source; - private readonly QuantizedFrame quantized; + private readonly IndexedImageFrame quantized; [MethodImpl(InliningOptions.ShortMethod)] public RowIntervalOperation( Rectangle bounds, ImageFrame source, - QuantizedFrame quantized) + IndexedImageFrame quantized) { this.bounds = bounds; this.source = source; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { - ReadOnlySpan quantizedPixelSpan = this.quantized.GetPixelSpan(); + ReadOnlySpan quantizedPixelSpan = this.quantized.GetPixelBufferSpan(); ReadOnlySpan paletteSpan = this.quantized.Palette.Span; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs deleted file mode 100644 index d5facbe63a..0000000000 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Processing.Processors.Quantization -{ - /// - /// Represents a quantized image frame where the pixels indexed by a color palette. - /// - /// The pixel format. - public sealed class QuantizedFrame : IDisposable - where TPixel : unmanaged, IPixel - { - private IMemoryOwner palette; - private IMemoryOwner pixels; - private bool isDisposed; - - /// - /// Initializes a new instance of the class. - /// - /// Used to allocated memory for image processing operations. - /// The image width. - /// The image height. - /// The color palette. - internal QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, ReadOnlySpan palette) - { - Guard.MustBeGreaterThan(width, 0, nameof(width)); - Guard.MustBeGreaterThan(height, 0, nameof(height)); - - this.Width = width; - this.Height = height; - this.pixels = memoryAllocator.AllocateManagedByteBuffer(width * height, AllocationOptions.Clean); - - this.palette = memoryAllocator.Allocate(palette.Length); - palette.CopyTo(this.palette.GetSpan()); - } - - /// - /// Gets the width of this . - /// - public int Width { get; } - - /// - /// Gets the height of this . - /// - public int Height { get; } - - /// - /// Gets the color palette of this . - /// - public ReadOnlyMemory Palette - { - [MethodImpl(InliningOptions.ShortMethod)] - get { return this.palette.Memory; } - } - - /// - /// Gets the pixels of this . - /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public Span GetPixelSpan() => this.pixels.GetSpan(); - - /// - /// Gets the representation of the pixels as a of contiguous memory - /// at row beginning from the the first pixel on that row. - /// - /// The row. - /// The pixel row as a . - [MethodImpl(InliningOptions.ShortMethod)] - public Span GetPixelRowSpan(int rowIndex) - => this.GetPixelSpan().Slice(rowIndex * this.Width, this.Width); - - /// - public void Dispose() - { - if (!this.isDisposed) - { - return; - } - - this.isDisposed = true; - this.pixels?.Dispose(); - this.palette?.Dispose(); - this.pixels = null; - this.palette = null; - } - } -} diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index f50282f9a8..60f3a0a2af 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -66,10 +66,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// private const int TableLength = IndexCount * IndexCount * IndexCount * IndexAlphaCount; - private IMemoryOwner moments; - private IMemoryOwner tag; - private IMemoryOwner palette; - private int colors; + private IMemoryOwner momentsOwner; + private IMemoryOwner tagsOwner; + private IMemoryOwner paletteOwner; + private int maxColors; private readonly Box[] colorCube; private EuclideanPixelMap pixelMap; private readonly bool isDithering; @@ -88,12 +88,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.Configuration = configuration; this.Options = options; - this.colors = this.Options.MaxColors; + this.maxColors = this.Options.MaxColors; this.memoryAllocator = this.Configuration.MemoryAllocator; - this.moments = this.memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.tag = this.memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.palette = this.memoryAllocator.Allocate(this.colors, AllocationOptions.Clean); - this.colorCube = new Box[this.colors]; + this.momentsOwner = this.memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + this.tagsOwner = this.memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + this.paletteOwner = this.memoryAllocator.Allocate(this.maxColors, AllocationOptions.Clean); + this.colorCube = new Box[this.maxColors]; this.isDisposed = false; this.pixelMap = default; this.isDithering = this.isDithering = !(this.Options.Dither is null); @@ -107,19 +107,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly QuantizedFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// - public ReadOnlySpan BuildPalette(ImageFrame source, Rectangle bounds) + public ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) { this.Build3DHistogram(source, bounds); this.Get3DMoments(this.memoryAllocator); this.BuildCube(); - ReadOnlySpan momentsSpan = this.moments.GetSpan(); - Span paletteSpan = this.palette.GetSpan(); - for (int k = 0; k < this.colors; k++) + ReadOnlySpan momentsSpan = this.momentsOwner.GetSpan(); + Span paletteSpan = this.paletteOwner.GetSpan(); + for (int k = 0; k < this.maxColors; k++) { this.Mark(ref this.colorCube[k], (byte)k); @@ -132,9 +132,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - paletteSpan = paletteSpan.Slice(0, this.colors); - this.pixelMap = new EuclideanPixelMap(this.Configuration, this.palette.Memory, paletteSpan.Length); - return paletteSpan; + ReadOnlyMemory result = this.paletteOwner.Memory.Slice(0, this.maxColors); + this.pixelMap = new EuclideanPixelMap(this.Configuration, result); + return result; } /// @@ -153,9 +153,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization int b = rgba.B >> (8 - IndexBits); int a = rgba.A >> (8 - IndexAlphaBits); - ReadOnlySpan tagSpan = this.tag.GetSpan(); + ReadOnlySpan tagSpan = this.tagsOwner.GetSpan(); byte index = tagSpan[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)]; - ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.pixelMap.GetPaletteSpan()); + ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.pixelMap.Palette.Span); match = Unsafe.Add(ref paletteRef, index); return index; } @@ -166,12 +166,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!this.isDisposed) { this.isDisposed = true; - this.moments?.Dispose(); - this.tag?.Dispose(); - this.palette?.Dispose(); - this.moments = null; - this.tag = null; - this.palette = null; + this.momentsOwner?.Dispose(); + this.tagsOwner?.Dispose(); + this.paletteOwner?.Dispose(); + this.momentsOwner = null; + this.tagsOwner = null; + this.paletteOwner = null; } } @@ -350,7 +350,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The bounds within the source image to quantize. private void Build3DHistogram(ImageFrame source, Rectangle bounds) { - Span momentSpan = this.moments.GetSpan(); + Span momentSpan = this.momentsOwner.GetSpan(); // Build up the 3-D color histogram using IMemoryOwner buffer = this.memoryAllocator.Allocate(bounds.Width); @@ -384,7 +384,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization using IMemoryOwner volume = allocator.Allocate(IndexCount * IndexAlphaCount); using IMemoryOwner area = allocator.Allocate(IndexAlphaCount); - Span momentSpan = this.moments.GetSpan(); + Span momentSpan = this.momentsOwner.GetSpan(); Span volumeSpan = volume.GetSpan(); Span areaSpan = area.GetSpan(); int baseIndex = GetPaletteIndex(1, 0, 0, 0); @@ -426,7 +426,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The . private double Variance(ref Box cube) { - ReadOnlySpan momentSpan = this.moments.GetSpan(); + ReadOnlySpan momentSpan = this.momentsOwner.GetSpan(); Moment volume = Volume(ref cube, momentSpan); Moment variance = @@ -467,7 +467,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The . private float Maximize(ref Box cube, int direction, int first, int last, out int cut, Moment whole) { - ReadOnlySpan momentSpan = this.moments.GetSpan(); + ReadOnlySpan momentSpan = this.momentsOwner.GetSpan(); Moment bottom = Bottom(ref cube, direction, momentSpan); float max = 0F; @@ -513,7 +513,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Returns a value indicating whether the box has been split. private bool Cut(ref Box set1, ref Box set2) { - ReadOnlySpan momentSpan = this.moments.GetSpan(); + ReadOnlySpan momentSpan = this.momentsOwner.GetSpan(); Moment whole = Volume(ref set1, momentSpan); float maxR = this.Maximize(ref set1, 3, set1.RMin + 1, set1.RMax, out int cutR, whole); @@ -598,7 +598,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// A label. private void Mark(ref Box cube, byte label) { - Span tagSpan = this.tag.GetSpan(); + Span tagSpan = this.tagsOwner.GetSpan(); for (int r = cube.RMin + 1; r <= cube.RMax; r++) { @@ -620,7 +620,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// private void BuildCube() { - Span vv = stackalloc double[this.colors]; + Span vv = stackalloc double[this.maxColors]; ref Box cube = ref this.colorCube[0]; cube.RMin = cube.GMin = cube.BMin = cube.AMin = 0; @@ -629,7 +629,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization int next = 0; - for (int i = 1; i < this.colors; i++) + for (int i = 1; i < this.maxColors; i++) { ref Box nextCube = ref this.colorCube[next]; ref Box currentCube = ref this.colorCube[i]; @@ -658,7 +658,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (temp <= 0D) { - this.colors = i + 1; + this.maxColors = i + 1; break; } } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index cd93ab0cf8..7e4eced8fc 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -71,10 +71,10 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(this.Configuration)) - using (QuantizedFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) + using (IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { int index = this.GetTransparentIndex(quantized); - Assert.Equal(index, quantized.GetPixelSpan()[0]); + Assert.Equal(index, quantized.GetPixelBufferSpan()[0]); } } } @@ -101,27 +101,27 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(this.Configuration)) - using (QuantizedFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) + using (IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { int index = this.GetTransparentIndex(quantized); - Assert.Equal(index, quantized.GetPixelSpan()[0]); + Assert.Equal(index, quantized.GetPixelBufferSpan()[0]); } } } } - private int GetTransparentIndex(QuantizedFrame quantized) + private int GetTransparentIndex(IndexedImageFrame quantized) where TPixel : unmanaged, IPixel { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - Rgba32 trans = default; ReadOnlySpan paletteSpan = quantized.Palette.Span; - for (int i = paletteSpan.Length - 1; i >= 0; i--) - { - paletteSpan[i].ToRgba32(ref trans); + Span colorSpan = stackalloc Rgba32[QuantizerConstants.MaxColors].Slice(0, paletteSpan.Length); - if (trans.Equals(default)) + PixelOperations.Instance.ToRgba32(quantized.Configuration, paletteSpan, colorSpan); + for (int i = colorSpan.Length - 1; i >= 0; i--) + { + if (colorSpan[i].Equals(default)) { index = i; } diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index f3bcd0b955..2a0a02d942 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -21,13 +21,13 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config); - using QuantizedFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); - Assert.Equal(1, result.GetPixelSpan().Length); + Assert.Equal(1, result.GetPixelBufferSpan().Length); Assert.Equal(Color.Black, (Color)result.Palette.Span[0]); - Assert.Equal(0, result.GetPixelSpan()[0]); + Assert.Equal(0, result.GetPixelBufferSpan()[0]); } [Fact] @@ -40,13 +40,13 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config); - using QuantizedFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); - Assert.Equal(1, result.GetPixelSpan().Length); + Assert.Equal(1, result.GetPixelBufferSpan().Length); Assert.Equal(default, result.Palette.Span[0]); - Assert.Equal(0, result.GetPixelSpan()[0]); + Assert.Equal(0, result.GetPixelBufferSpan()[0]); } [Fact] @@ -85,19 +85,19 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config); - using QuantizedFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(256, result.Palette.Length); - Assert.Equal(256, result.GetPixelSpan().Length); + Assert.Equal(256, result.GetPixelBufferSpan().Length); var actualImage = new Image(1, 256); ReadOnlySpan paletteSpan = result.Palette.Span; - int paletteCount = result.Palette.Length - 1; + int paletteCount = paletteSpan.Length - 1; for (int y = 0; y < actualImage.Height; y++) { Span row = actualImage.GetPixelRowSpan(y); - ReadOnlySpan quantizedPixelSpan = result.GetPixelSpan(); + ReadOnlySpan quantizedPixelSpan = result.GetPixelBufferSpan(); int yy = y * actualImage.Width; for (int x = 0; x < actualImage.Width; x++) @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config); - using QuantizedFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(48, result.Palette.Length); } @@ -152,17 +152,17 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) - using (QuantizedFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) + using (IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { Assert.Equal(4 * 8, result.Palette.Length); - Assert.Equal(256, result.GetPixelSpan().Length); + Assert.Equal(256, result.GetPixelBufferSpan().Length); ReadOnlySpan paletteSpan = result.Palette.Span; - int paletteCount = result.Palette.Length - 1; + int paletteCount = paletteSpan.Length - 1; for (int y = 0; y < actualImage.Height; y++) { Span row = actualImage.GetPixelRowSpan(y); - ReadOnlySpan quantizedPixelSpan = result.GetPixelSpan(); + ReadOnlySpan quantizedPixelSpan = result.GetPixelBufferSpan(); int yy = y * actualImage.Width; for (int x = 0; x < actualImage.Width; x++) From 89c5fe249f5fa8ab5f8631fa4a1d8b33b66058eb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 5 Mar 2020 16:34:44 +1100 Subject: [PATCH 042/213] Introduce palette property --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 3 +- .../PaletteDitherProcessor{TPixel}.cs | 16 ++++---- ...tensions.cs => FrameQuantizerUtilities.cs} | 38 ++++++++++++++++--- .../Quantization/IFrameQuantizer{TPixel}.cs | 11 +++++- .../OctreeFrameQuantizer{TPixel}.cs | 22 ++++++++--- .../PaletteFrameQuantizer{TPixel}.cs | 10 +++-- .../Quantization/WuFrameQuantizer{TPixel}.cs | 22 ++++++++--- 7 files changed, 91 insertions(+), 31 deletions(-) rename src/ImageSharp/Processing/Processors/Quantization/{FrameQuantizerExtensions.cs => FrameQuantizerUtilities.cs} (77%) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 6caaa1df02..8a26fb51c0 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -384,8 +384,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - int stride = this.currentScanline.Length(); - quantized.GetPixelBufferSpan().Slice(row * stride, stride).CopyTo(this.currentScanline.GetSpan()); + quantized.GetPixelRowSpan(row).CopyTo(this.currentScanline.GetSpan()); } break; diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 1f554536c6..e0dd4eae18 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -4,7 +4,6 @@ using System; using System.Buffers; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -19,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering { private readonly DitherProcessor ditherProcessor; private readonly IDither dither; - private IMemoryOwner paletteMemory; + private IMemoryOwner paletteOwner; private bool isDisposed; /// @@ -35,12 +34,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering this.dither = definition.Dither; ReadOnlySpan sourcePalette = definition.Palette.Span; - this.paletteMemory = this.Configuration.MemoryAllocator.Allocate(sourcePalette.Length); - Color.ToPixel(this.Configuration, sourcePalette, this.paletteMemory.Memory.Span); + this.paletteOwner = this.Configuration.MemoryAllocator.Allocate(sourcePalette.Length); + Color.ToPixel(this.Configuration, sourcePalette, this.paletteOwner.Memory.Span); this.ditherProcessor = new DitherProcessor( this.Configuration, - this.paletteMemory.Memory, + this.paletteOwner.Memory, definition.DitherScale); } @@ -59,14 +58,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering return; } + this.isDisposed = true; if (disposing) { - this.paletteMemory?.Dispose(); + this.paletteOwner.Dispose(); } - this.paletteMemory = null; - - this.isDisposed = true; + this.paletteOwner = null; base.Dispose(disposing); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs similarity index 77% rename from src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs rename to src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs index 26da6a3976..4d75042ea3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs @@ -11,10 +11,28 @@ using SixLabors.ImageSharp.Processing.Processors.Dithering; namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// - /// Contains extension methods for frame quantizers. + /// Contains utility methods for instances. /// - public static class FrameQuantizerExtensions + public static class FrameQuantizerUtilities { + /// + /// Helper method for throwing an exception when a frame quantizer palette has + /// been requested but not built yet. + /// + /// The pixel format. + /// The frame quantizer palette. + /// + /// The palette has not been built via + /// + public static void CheckPaletteState(in ReadOnlyMemory palette) + where TPixel : unmanaged, IPixel + { + if (palette.Equals(default)) + { + throw new InvalidOperationException("Frame Quantizer palette has not been built."); + } + } + /// /// Quantizes an image frame and return the resulting output pixels. /// @@ -37,8 +55,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization var interest = Rectangle.Intersect(source.Bounds(), bounds); // Collect the palette. Required before the second pass runs. - ReadOnlyMemory palette = quantizer.BuildPalette(source, interest); - var destination = new IndexedImageFrame(quantizer.Configuration, interest.Width, interest.Height, palette); + quantizer.BuildPalette(source, interest); + + var destination = new IndexedImageFrame( + quantizer.Configuration, + interest.Width, + interest.Height, + quantizer.Palette); if (quantizer.Options.Dither is null) { @@ -67,7 +90,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (dither is null) { - var operation = new RowIntervalOperation(ref quantizer, source, destination, bounds); + var operation = new RowIntervalOperation( + ref quantizer, + source, + destination, + bounds); + ParallelRowIterator.IterateRowIntervals( quantizer.Configuration, bounds, diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index 64caad3e20..cc87715ebd 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -23,13 +23,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// QuantizerOptions Options { get; } + /// + /// Gets the quantized color palette. + /// + /// + /// The palette has not been built via . + /// + ReadOnlyMemory Palette { get; } + /// /// Builds the quantized palette from the given image frame and bounds. /// /// The source image frame. /// The region of interest bounds. - /// The palette. - ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds); + void BuildPalette(ImageFrame source, Rectangle bounds); /// /// Quantizes an image frame and return the resulting output pixels. diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 6c31fca7fe..433ac45677 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -23,6 +23,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private readonly int maxColors; private readonly Octree octree; private IMemoryOwner paletteOwner; + private ReadOnlyMemory palette; private EuclideanPixelMap pixelMap; private readonly bool isDithering; private bool isDisposed; @@ -44,6 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.maxColors = this.Options.MaxColors; this.octree = new Octree(ImageMaths.GetBitsNeededForColorDepth(this.maxColors).Clamp(1, 8)); this.paletteOwner = configuration.MemoryAllocator.Allocate(this.maxColors, AllocationOptions.Clean); + this.palette = default; this.pixelMap = default; this.isDithering = !(this.Options.Dither is null); this.isDisposed = false; @@ -56,13 +58,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public QuantizerOptions Options { get; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + public ReadOnlyMemory Palette + { + get + { + FrameQuantizerUtilities.CheckPaletteState(in this.palette); + return this.palette; + } + } /// [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) + public void BuildPalette(ImageFrame source, Rectangle bounds) { using IMemoryOwner buffer = this.Configuration.MemoryAllocator.Allocate(bounds.Width); Span bufferSpan = buffer.GetSpan(); @@ -90,9 +97,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ReadOnlyMemory result = this.paletteOwner.Memory.Slice(0, Math.Min(paletteIndex + 2, QuantizerConstants.MaxColors)); this.pixelMap = new EuclideanPixelMap(this.Configuration, result); - return result; + this.palette = result; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => FrameQuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + /// [MethodImpl(InliningOptions.ShortMethod)] public readonly byte GetQuantizedColor(TPixel color, out TPixel match) diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index d371168554..ade73e2d02 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -43,15 +43,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public QuantizerOptions Options { get; } + /// + public ReadOnlyMemory Palette => this.pixelMap.Palette; + /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => FrameQuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] - public readonly ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) - => this.pixelMap.Palette; + public void BuildPalette(ImageFrame source, Rectangle bounds) + { + } /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 60f3a0a2af..67a46375d7 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -69,6 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private IMemoryOwner momentsOwner; private IMemoryOwner tagsOwner; private IMemoryOwner paletteOwner; + private ReadOnlyMemory palette; private int maxColors; private readonly Box[] colorCube; private EuclideanPixelMap pixelMap; @@ -93,6 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.momentsOwner = this.memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); this.tagsOwner = this.memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); this.paletteOwner = this.memoryAllocator.Allocate(this.maxColors, AllocationOptions.Clean); + this.palette = default; this.colorCube = new Box[this.maxColors]; this.isDisposed = false; this.pixelMap = default; @@ -106,12 +108,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public QuantizerOptions Options { get; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerExtensions.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + public ReadOnlyMemory Palette + { + get + { + FrameQuantizerUtilities.CheckPaletteState(in this.palette); + return this.palette; + } + } /// - public ReadOnlyMemory BuildPalette(ImageFrame source, Rectangle bounds) + public void BuildPalette(ImageFrame source, Rectangle bounds) { this.Build3DHistogram(source, bounds); this.Get3DMoments(this.memoryAllocator); @@ -134,9 +141,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ReadOnlyMemory result = this.paletteOwner.Memory.Slice(0, this.maxColors); this.pixelMap = new EuclideanPixelMap(this.Configuration, result); - return result; + this.palette = result; } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) + => FrameQuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + /// public readonly byte GetQuantizedColor(TPixel color, out TPixel match) { From 01efb0975852dfe11faf7eabd63a51379a26ef43 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 5 Mar 2020 17:07:25 +1100 Subject: [PATCH 043/213] Faster png palette encoding. --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 65 +++++++++---------- .../Quantization/IndexedImageFrame{TPixel}.cs | 1 + 2 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 8a26fb51c0..25ccf7bd16 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -555,49 +555,44 @@ namespace SixLabors.ImageSharp.Formats.Png // Grab the palette and write it to the stream. ReadOnlySpan palette = quantized.Palette.Span; - int paletteLength = Math.Min(palette.Length, QuantizerConstants.MaxColors); - int colorTableLength = paletteLength * 3; - bool anyAlpha = false; + int paletteLength = palette.Length; + int colorTableLength = paletteLength * Unsafe.SizeOf(); + bool hasAlpha = false; - using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) - using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(paletteLength)) - { - ref byte colorTableRef = ref MemoryMarshal.GetReference(colorTable.GetSpan()); - ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); - ReadOnlySpan quantizedSpan = quantized.GetPixelBufferSpan(); - - Rgba32 rgba = default; - - for (int i = 0; i < paletteLength; i++) - { - if (quantizedSpan.IndexOf((byte)i) > -1) - { - int offset = i * 3; - palette[i].ToRgba32(ref rgba); + using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength); + using IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(paletteLength); - byte alpha = rgba.A; + ref Rgb24 colorTableRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(colorTable.GetSpan())); + ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); - Unsafe.Add(ref colorTableRef, offset) = rgba.R; - Unsafe.Add(ref colorTableRef, offset + 1) = rgba.G; - Unsafe.Add(ref colorTableRef, offset + 2) = rgba.B; + // Bulk convert our palette to RGBA to allow assignment to tables. + // Palette length maxes out at 256 so safe to stackalloc. + Span rgbaPaletteSpan = stackalloc Rgba32[palette.Length]; + PixelOperations.Instance.ToRgba32(quantized.Configuration, quantized.Palette.Span, rgbaPaletteSpan); + ref Rgba32 rgbaPaletteRef = ref MemoryMarshal.GetReference(rgbaPaletteSpan); - if (alpha > this.options.Threshold) - { - alpha = byte.MaxValue; - } + // Loop, assign, and extract alpha values from the palette. + for (int i = 0; i < paletteLength; i++) + { + Rgba32 rgba = Unsafe.Add(ref rgbaPaletteRef, i); + byte alpha = rgba.A; - anyAlpha = anyAlpha || alpha < byte.MaxValue; - Unsafe.Add(ref alphaTableRef, i) = alpha; - } + Unsafe.Add(ref colorTableRef, i) = rgba.Rgb; + if (alpha > this.options.Threshold) + { + alpha = byte.MaxValue; } - this.WriteChunk(stream, PngChunkType.Palette, colorTable.Array, 0, colorTableLength); + hasAlpha = hasAlpha || alpha < byte.MaxValue; + Unsafe.Add(ref alphaTableRef, i) = alpha; + } - // Write the transparency data - if (anyAlpha) - { - this.WriteChunk(stream, PngChunkType.Transparency, alphaTable.Array, 0, paletteLength); - } + this.WriteChunk(stream, PngChunkType.Palette, colorTable.Array, 0, colorTableLength); + + // Write the transparency data + if (hasAlpha) + { + this.WriteChunk(stream, PngChunkType.Transparency, alphaTable.Array, 0, paletteLength); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs index 42aadb5fd0..ac737f452f 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs @@ -32,6 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization internal IndexedImageFrame(Configuration configuration, int width, int height, ReadOnlyMemory palette) { Guard.NotNull(configuration, nameof(configuration)); + Guard.MustBeLessThanOrEqualTo(palette.Length, QuantizerConstants.MaxColors, nameof(palette)); Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); From fb26d0ebd193af3e1aec999e911cc98d96abecb5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 5 Mar 2020 17:33:44 +1100 Subject: [PATCH 044/213] Faster Gif transparency lookup. --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 29 ++++++++------------ 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 29e2e8fe2e..dcd0be34b0 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -86,7 +85,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } // Get the number of bits. - this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length); // Write the header. this.WriteHeader(stream); @@ -193,7 +192,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } } - this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length); this.WriteGraphicalControlExtension(frameMetadata, this.GetTransparentIndex(quantized), stream); this.WriteImageDescriptor(frame, true, stream); this.WriteColorTable(quantized, stream); @@ -218,21 +217,18 @@ namespace SixLabors.ImageSharp.Formats.Gif where TPixel : unmanaged, IPixel { // Transparent pixels are much more likely to be found at the end of a palette. + // Palette length maxes out at 256 so safe to stackalloc. int index = -1; - int length = quantized.Palette.Length; + ReadOnlySpan paletteSpan = quantized.Palette.Span; + Span rgbaSpan = stackalloc Rgba32[paletteSpan.Length]; + PixelOperations.Instance.ToRgba32(quantized.Configuration, paletteSpan, rgbaSpan); + ref Rgba32 rgbaSpanRef = ref MemoryMarshal.GetReference(rgbaSpan); - using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(length)) + for (int i = rgbaSpan.Length - 1; i >= 0; i--) { - Span rgbaSpan = rgbaBuffer.GetSpan(); - ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette.Span, rgbaSpan); - - for (int i = quantized.Palette.Length - 1; i >= 0; i--) + if (Unsafe.Add(ref rgbaSpanRef, i).Equals(default)) { - if (Unsafe.Add(ref paletteRef, i).Equals(default)) - { - index = i; - } + index = i; } } @@ -451,15 +447,14 @@ namespace SixLabors.ImageSharp.Formats.Gif where TPixel : unmanaged, IPixel { // The maximum number of colors for the bit depth - int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; - int pixelCount = image.Palette.Length; + int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * Unsafe.SizeOf(); using IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength, AllocationOptions.Clean); PixelOperations.Instance.ToRgb24Bytes( this.configuration, image.Palette.Span, colorTable.GetSpan(), - pixelCount); + image.Palette.Length); stream.Write(colorTable.Array, 0, colorTableLength); } From 5ca7408a72f289a60c9ef705dc9a9ee829590e8f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 5 Mar 2020 17:33:51 +1100 Subject: [PATCH 045/213] Cleanup --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- .../Formats/Gif/GifEncoderTests.cs | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 25ccf7bd16..8dbfc25d7f 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -567,7 +567,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Bulk convert our palette to RGBA to allow assignment to tables. // Palette length maxes out at 256 so safe to stackalloc. - Span rgbaPaletteSpan = stackalloc Rgba32[palette.Length]; + Span rgbaPaletteSpan = stackalloc Rgba32[paletteLength]; PixelOperations.Instance.ToRgba32(quantized.Configuration, quantized.Palette.Span, rgbaPaletteSpan); ref Rgba32 rgbaPaletteRef = ref MemoryMarshal.GetReference(rgbaPaletteSpan); diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 4adffca4ff..588f652548 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -5,7 +5,6 @@ using System.IO; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; @@ -26,23 +25,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif { TestImages.Gif.Ratio4x1, 4, 1, PixelResolutionUnit.AspectRatio } }; - [Theory] - [WithFile(TestImages.Bmp.Car, PixelTypes.Rgba32)] - public void EncodeAllocationCheck(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - GifEncoder encoder = new GifEncoder - { - Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 }) - }; - - using (Image image = provider.GetImage()) - { - // Always save as we need to compare the encoded output. - provider.Utility.SaveTestOutputFile(image, "gif", encoder); - } - } - [Theory] [WithTestPatternImages(100, 100, TestPixelTypes, false)] [WithTestPatternImages(100, 100, TestPixelTypes, false)] From dd32cdfd1b4e6db203f81313bedf51db4e5747d5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 6 Mar 2020 22:36:29 +1100 Subject: [PATCH 046/213] Remove stackalloc --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 6 ++++-- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 ++-- .../Processors/Quantization/WuFrameQuantizer{TPixel}.cs | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index a591eaf3ba..8875409309 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -217,10 +218,11 @@ namespace SixLabors.ImageSharp.Formats.Gif where TPixel : unmanaged, IPixel { // Transparent pixels are much more likely to be found at the end of a palette. - // Palette length maxes out at 256 so safe to stackalloc. int index = -1; ReadOnlySpan paletteSpan = quantized.Palette.Span; - Span rgbaSpan = stackalloc Rgba32[paletteSpan.Length]; + + using IMemoryOwner rgbaOwner = quantized.Configuration.MemoryAllocator.Allocate(paletteSpan.Length); + Span rgbaSpan = rgbaOwner.GetSpan(); PixelOperations.Instance.ToRgba32(quantized.Configuration, paletteSpan, rgbaSpan); ref Rgba32 rgbaSpanRef = ref MemoryMarshal.GetReference(rgbaSpan); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 2d8d66c33d..45e1ffd2d7 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -566,8 +566,8 @@ namespace SixLabors.ImageSharp.Formats.Png ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); // Bulk convert our palette to RGBA to allow assignment to tables. - // Palette length maxes out at 256 so safe to stackalloc. - Span rgbaPaletteSpan = stackalloc Rgba32[paletteLength]; + using IMemoryOwner rgbaOwner = quantized.Configuration.MemoryAllocator.Allocate(paletteLength); + Span rgbaPaletteSpan = rgbaOwner.GetSpan(); PixelOperations.Instance.ToRgba32(quantized.Configuration, quantized.Palette.Span, rgbaPaletteSpan); ref Rgba32 rgbaPaletteRef = ref MemoryMarshal.GetReference(rgbaPaletteSpan); diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 67a46375d7..d15db74e62 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -632,7 +632,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// private void BuildCube() { - Span vv = stackalloc double[this.maxColors]; + // Store the volume variance. + using IMemoryOwner vvOwner = this.Configuration.MemoryAllocator.Allocate(this.maxColors); + Span vv = vvOwner.GetSpan(); ref Box cube = ref this.colorCube[0]; cube.RMin = cube.GMin = cube.BMin = cube.AMin = 0; From 0e83ee3c4fd935130909c25d44936fad24c4d83f Mon Sep 17 00:00:00 2001 From: Greg Date: Sat, 7 Mar 2020 21:18:03 +0100 Subject: [PATCH 047/213] Fix typos in FilterExtensions.cs --- .../Processing/Extensions/Filters/FilterExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs index 088f618840..f89540e245 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing public static class FilterExtensions { /// - /// Filters an image but the given color matrix + /// Filters an image by the given color matrix /// /// The image this method extends. /// The filter color matrix @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Processing => source.ApplyProcessor(new FilterProcessor(matrix)); /// - /// Filters an image but the given color matrix + /// Filters an image by the given color matrix /// /// The image this method extends. /// The filter color matrix @@ -32,4 +32,4 @@ namespace SixLabors.ImageSharp.Processing public static IImageProcessingContext Filter(this IImageProcessingContext source, ColorMatrix matrix, Rectangle rectangle) => source.ApplyProcessor(new FilterProcessor(matrix), rectangle); } -} \ No newline at end of file +} From 91796ce96df71ea604f80e63a54ab82c2e2bec46 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 9 Mar 2020 20:08:26 +1100 Subject: [PATCH 048/213] Update submodule and remove build copy. --- shared-infrastructure | 2 +- src/Directory.Build.targets | 13 - .../Common/Helpers/Guard.Numeric.cs | 1154 ----------------- src/ImageSharp/ImageSharp.csproj | 16 +- 4 files changed, 2 insertions(+), 1183 deletions(-) delete mode 100644 src/ImageSharp/Common/Helpers/Guard.Numeric.cs diff --git a/shared-infrastructure b/shared-infrastructure index 8dfef29f18..ea561c249b 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 8dfef29f1838da76be9596f1a2f1be6d93e453d3 +Subproject commit ea561c249ba86352fe3b69e612b8072f3652eacb diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 055a6803e7..d7171aa0f6 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -55,14 +55,6 @@ - - @@ -70,11 +62,6 @@ - - diff --git a/src/ImageSharp/Common/Helpers/Guard.Numeric.cs b/src/ImageSharp/Common/Helpers/Guard.Numeric.cs deleted file mode 100644 index 72262e0b9e..0000000000 --- a/src/ImageSharp/Common/Helpers/Guard.Numeric.cs +++ /dev/null @@ -1,1154 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; - -namespace SixLabors -{ - /// - /// Provides methods to protect against invalid parameters. - /// - internal static partial class Guard - { - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(byte value, byte max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(byte value, byte max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(byte value, byte min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(byte value, byte min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(byte value, byte min, byte max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(sbyte value, sbyte max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(sbyte value, sbyte max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(sbyte value, sbyte min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(sbyte value, sbyte min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(sbyte value, sbyte min, sbyte max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(short value, short max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(short value, short max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(short value, short min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(short value, short min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(short value, short min, short max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(ushort value, ushort max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(ushort value, ushort max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(ushort value, ushort min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(ushort value, ushort min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(ushort value, ushort min, ushort max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(char value, char max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(char value, char max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(char value, char min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(char value, char min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(char value, char min, char max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(int value, int max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(int value, int max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(int value, int min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(int value, int min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(int value, int min, int max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(uint value, uint max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(uint value, uint max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(uint value, uint min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(uint value, uint min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(uint value, uint min, uint max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(float value, float max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(float value, float max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(float value, float min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(float value, float min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(float value, float min, float max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(long value, long max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(long value, long max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(long value, long min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(long value, long min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(long value, long min, long max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(ulong value, ulong max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(ulong value, ulong max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(ulong value, ulong min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(ulong value, ulong min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(ulong value, ulong min, ulong max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(double value, double max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(double value, double max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(double value, double min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(double value, double min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(double value, double min, double max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - - /// - /// Ensures that the specified value is less than a maximum value. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThan(decimal value, decimal max, string parameterName) - { - if (value >= max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThan(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is less than or equal to a maximum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeLessThanOrEqualTo(decimal value, decimal max, string parameterName) - { - if (value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeLessThanOrEqualTo(value, max, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThan(decimal value, decimal min, string parameterName) - { - if (value <= min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThan(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value - /// and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeGreaterThanOrEqualTo(decimal value, decimal min, string parameterName) - { - if (value < min) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeGreaterThanOrEqualTo(value, min, parameterName); - } - } - - /// - /// Verifies that the specified value is greater than or equal to a minimum value and less than - /// or equal to a maximum value and throws an exception if it is not. - /// - /// The target value, which should be validated. - /// The minimum value. - /// The maximum value. - /// The name of the parameter that is to be checked. - /// - /// is less than the minimum value of greater than the maximum value. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void MustBeBetweenOrEqualTo(decimal value, decimal min, decimal max, string parameterName) - { - if (value < min || value > max) - { - ThrowHelper.ThrowArgumentOutOfRangeExceptionForMustBeBetweenOrEqualTo(value, min, max, parameterName); - } - } - } -} diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 24d4f4a005..baf4a2ce19 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -36,17 +36,7 @@ - - - - True - True - Guard.Numeric.tt - - + True True @@ -212,10 +202,6 @@ DefaultPixelBlenders.Generated.cs TextTemplatingFileGenerator - - Guard.Numeric.cs - TextTemplatingFileGenerator - From 10616c80a5ea3d84466bcb6e28c0a034eec18ce6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 10 Mar 2020 01:04:45 +0100 Subject: [PATCH 049/213] cleanup and fix build errors --- src/ImageSharp/ImageSharp.csproj | 3 +-- .../Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs | 5 ++++- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 1 + .../Codecs/Jpeg/YCbCrColorConversion.cs | 2 +- tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs | 2 +- tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 3 +-- .../ImageSharp.Tests.ProfilingSandbox.csproj | 3 +-- tests/ImageSharp.Tests/Common/SimdUtilsTests.cs | 1 - tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +-- .../ProfilingBenchmarks/JpegProfilingBenchmarks.cs | 2 +- .../ProfilingBenchmarks/ResizeProfilingBenchmarks.cs | 2 +- 11 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 0d803475a4..be0e9032b6 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -10,8 +10,7 @@ $(packageversion) 0.0.1 - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 true true diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs index b97ca14f38..55d66d488d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -5,12 +5,15 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + +#if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +#endif + using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; -using SixLabors.ImageSharp.Memory; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index bad60d8eea..1696623ef1 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -44,6 +44,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + #pragma warning disable SA1115 [Params( TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs index f8e7f7fb80..1daf9b4d5a 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs @@ -11,7 +11,7 @@ using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { - [Config(typeof(Config.ShortCore31))] + [Config(typeof(Config.ShortClr))] public class YCbCrColorConversion { private Buffer2D[] input; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 04043c2f7b..73c9116fd4 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -21,7 +21,7 @@ using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - [Config(typeof(Config.ShortCore31))] + [Config(typeof(Config.ShortClr))] public abstract class FromVector4 where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 101d279569..f380d0a6a9 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -5,8 +5,7 @@ ImageSharp.Benchmarks Exe SixLabors.ImageSharp.Benchmarks - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 false false diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index f9e6c9da59..7c80316930 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -8,8 +8,7 @@ false SixLabors.ImageSharp.Tests.ProfilingSandbox win7-x64 - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 SixLabors.ImageSharp.Tests.ProfilingSandbox.Program false diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 1ab854c009..ef554a0110 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; using SixLabors.ImageSharp.Common.Tuples; using Xunit; diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index d5c8ef16ee..fdb280ca99 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,8 +2,7 @@ - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 True True SixLabors.ImageSharp.Tests diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index 358a5d0a01..0b63d63775 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, 5 } }; - [Theory] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName, int executionCount) { diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs index 9b8a3d5a35..ba5eb532b2 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks public int ExecutionCount { get; set; } = 50; - [Theory] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [InlineData(100, 100)] [InlineData(2000, 2000)] public void ResizeBicubic(int width, int height) From 687b48a1b035b9feb38b76cc85b27221ca884768 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 10 Mar 2020 01:15:53 +0100 Subject: [PATCH 050/213] reference MagicScaler code --- src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs index 85f73776c2..bbdc95a138 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs @@ -48,6 +48,10 @@ namespace SixLabors.ImageSharp /// /// Implementation of , which is faster on new .NET runtime. /// + /// + /// Implementation is based on MagicScaler code: + /// https://github.com/saucecontrol/PhotoSauce/blob/a9bd6e5162d2160419f0cf743fd4f536c079170b/src/MagicScaler/Magic/Processors/ConvertersFloat.cs#L453-L477 + /// internal static void BulkConvertNormalizedFloatToByteClampOverflows( ReadOnlySpan source, Span dest) From c61c3d71b6742c059f259ccbb1a92247d8d7ce77 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 10 Mar 2020 01:23:46 +0100 Subject: [PATCH 051/213] CopyTo -> ScaledCopyTo --- ...ock8x8F.CopyTo.cs => Block8x8F.ScaledCopyTo.cs} | 6 +++--- .../Formats/Jpeg/Components/Block8x8F.cs | 14 +++++++------- .../Components/Decoder/JpegBlockPostProcessor.cs | 2 +- .../Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs | 2 +- .../ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs | 10 +++++----- tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs | 10 +++++----- ...ferenceImplementations.LLM_FloatingPoint_DCT.cs | 4 ++-- 7 files changed, 24 insertions(+), 24 deletions(-) rename src/ImageSharp/Formats/Jpeg/Components/{Block8x8F.CopyTo.cs => Block8x8F.ScaledCopyTo.cs} (94%) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs similarity index 94% rename from src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs index b7301f3e9c..064ca75539 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs @@ -15,14 +15,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical scale factors. /// [MethodImpl(InliningOptions.ShortMethod)] - public void CopyTo(in BufferArea area, int horizontalScale, int verticalScale) + public void ScaledCopyTo(in BufferArea area, int horizontalScale, int verticalScale) { ref float areaOrigin = ref area.GetReferenceToOrigin(); - this.CopyTo(ref areaOrigin, area.Stride, horizontalScale, verticalScale); + this.ScaledCopyTo(ref areaOrigin, area.Stride, horizontalScale, verticalScale); } [MethodImpl(InliningOptions.ShortMethod)] - public void CopyTo(ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale) + public void ScaledCopyTo(ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale) { if (horizontalScale == 1 && verticalScale == 1) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index f2a81e5c83..868faceeaa 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -201,7 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Destination [MethodImpl(InliningOptions.ShortMethod)] - public void CopyTo(Span dest) + public void ScaledCopyTo(Span dest) { ref byte d = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); ref byte s = ref Unsafe.As(ref this); @@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Pointer to block /// Destination [MethodImpl(InliningOptions.ShortMethod)] - public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest) + public static unsafe void ScaledCopyTo(Block8x8F* blockPtr, Span dest) { float* fPtr = (float*)blockPtr; for (int i = 0; i < Size; i++) @@ -231,9 +231,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// The block pointer. /// The destination. [MethodImpl(InliningOptions.ShortMethod)] - public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest) + public static unsafe void ScaledCopyTo(Block8x8F* blockPtr, Span dest) { - blockPtr->CopyTo(dest); + blockPtr->ScaledCopyTo(dest); } /// @@ -241,7 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Destination [MethodImpl(InliningOptions.ShortMethod)] - public unsafe void CopyTo(float[] dest) + public unsafe void ScaledCopyTo(float[] dest) { fixed (void* ptr = &this.V0L) { @@ -253,7 +253,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy raw 32bit floating point data to dest /// /// Destination - public unsafe void CopyTo(Span dest) + public unsafe void ScaledCopyTo(Span dest) { fixed (Vector4* ptr = &this.V0L) { @@ -268,7 +268,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components public float[] ToArray() { var result = new float[Size]; - this.CopyTo(result); + this.ScaledCopyTo(result); return result; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs index 8c797463ba..db4b6a532b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // To be "more accurate", we need to emulate this by rounding! this.WorkspaceBlock1.NormalizeColorsAndRoundInplace(maximumValue); - this.WorkspaceBlock1.CopyTo( + this.WorkspaceBlock1.ScaledCopyTo( ref destAreaOrigin, destAreaStride, this.subSamplingDivisors.Width, diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index e8af799320..f55e46c3dc 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100, AllocationOptions.Clean)) { BufferArea area = buffer.GetArea(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); - block.CopyTo(area, horizontalFactor, verticalFactor); + block.ScaledCopyTo(area, horizontalFactor, verticalFactor); for (int y = 0; y < 8 * verticalFactor; y++) { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index 2af8dfe797..b3c911f566 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { var b = default(Block8x8F); b.LoadFrom(data); - b.CopyTo(mirror); + b.ScaledCopyTo(mirror); }); Assert.Equal(data, mirror); @@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { var b = default(Block8x8F); Block8x8F.LoadFrom(&b, data); - Block8x8F.CopyTo(&b, mirror); + Block8x8F.ScaledCopyTo(&b, mirror); }); Assert.Equal(data, mirror); @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { var v = default(Block8x8F); v.LoadFrom(data); - v.CopyTo(mirror); + v.ScaledCopyTo(mirror); }); Assert.Equal(data, mirror); @@ -175,7 +175,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg source.TransposeInto(ref dest); float[] actual = new float[64]; - dest.CopyTo(actual); + dest.ScaledCopyTo(actual); Assert.Equal(expected, actual); } @@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg dest.NormalizeColorsInplace(255); float[] array = new float[64]; - dest.CopyTo(array); + dest.ScaledCopyTo(array); this.Output.WriteLine("Result:"); this.PrintLinearData(array); foreach (float val in array) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs index ad44f0ad8b..683a79a8f4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FastFloatingPointDCT.IDCT8x4_LeftPart(ref source, ref dest); var actualDestArray = new float[64]; - dest.CopyTo(actualDestArray); + dest.ScaledCopyTo(actualDestArray); this.Print8x8Data(expectedDestArray); this.Output.WriteLine("**************"); @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FastFloatingPointDCT.IDCT8x4_RightPart(ref source, ref dest); var actualDestArray = new float[64]; - dest.CopyTo(actualDestArray); + dest.ScaledCopyTo(actualDestArray); this.Print8x8Data(expectedDestArray); this.Output.WriteLine("**************"); @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FastFloatingPointDCT.FDCT8x4_LeftPart(ref srcBlock, ref destBlock); var actualDest = new float[64]; - destBlock.CopyTo(actualDest); + destBlock.ScaledCopyTo(actualDest); Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f)); } @@ -148,7 +148,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FastFloatingPointDCT.FDCT8x4_RightPart(ref srcBlock, ref destBlock); var actualDest = new float[64]; - destBlock.CopyTo(actualDest); + destBlock.ScaledCopyTo(actualDest); Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f)); } @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg FastFloatingPointDCT.TransformFDCT(ref srcBlock, ref destBlock, ref temp2, false); var actualDest = new float[64]; - destBlock.CopyTo(actualDest); + destBlock.ScaledCopyTo(actualDest); Assert.Equal(actualDest, expectedDest, new ApproximateFloatComparer(1f)); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs index b3dafdbb89..533ecaca1a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils public static Block8x8F TransformIDCT(ref Block8x8F source) { float[] s = new float[64]; - source.CopyTo(s); + source.ScaledCopyTo(s); float[] d = new float[64]; float[] temp = new float[64]; @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils public static Block8x8F TransformFDCT_UpscaleBy8(ref Block8x8F source) { float[] s = new float[64]; - source.CopyTo(s); + source.ScaledCopyTo(s); float[] d = new float[64]; float[] temp = new float[64]; From 0f278e2b59a073da05740ef51eacfc2497efffe3 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 10 Mar 2020 01:57:59 +0100 Subject: [PATCH 052/213] fix test failure related to #824 --- .../Jpeg/Components/Decoder/JpegComponentPostProcessor.cs | 5 ++++- .../Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index b91287fb3d..d9fd9ac8b5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -95,7 +95,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Span colorBufferRow = this.ColorBuffer.GetRowSpan(yBuffer); Span blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock); - for (int xBlock = 0; xBlock < this.SizeInBlocks.Width; xBlock++) + // see: https://github.com/SixLabors/ImageSharp/issues/824 + int widthInBlocks = Math.Min(this.Component.SpectralBlocks.Width, this.SizeInBlocks.Width); + + for (int xBlock = 0; xBlock < widthInBlocks; xBlock++) { ref Block8x8 block = ref blockRow[xBlock]; int xBuffer = xBlock * this.blockAreaSize.Width; diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs index 20ee645fd5..f943598301 100644 --- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Memory protected override object GetPinnableObject() => this.Data; - [MethodImpl(MethodImplOptions.NoInlining)] + [MethodImpl(InliningOptions.ColdPath)] private static void ThrowObjectDisposedException() { throw new ObjectDisposedException("ArrayPoolMemoryAllocator.Buffer"); From ddb73eacd116e1734cddea4b54badf6377447bbb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 12 Mar 2020 22:52:10 +0100 Subject: [PATCH 053/213] improve naming in SimdUtils --- .../Helpers/SimdUtils.Avx2Intrinsics.cs | 10 ++++---- .../Helpers/SimdUtils.BasicIntrinsics256.cs | 24 +++++++++---------- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 20 ++++++++-------- .../SimdUtils.FallbackIntrinsics128.cs | 22 ++++++++--------- src/ImageSharp/Common/Helpers/SimdUtils.cs | 20 +++++++++------- .../Rgba32.PixelOperations.cs | 4 ++-- .../Utils/Vector4Converters.RgbaCompatible.cs | 4 ++-- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 20 ++++++++-------- 8 files changed, 63 insertions(+), 61 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs index bbdc95a138..ea1ffba05a 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs @@ -19,10 +19,10 @@ namespace SixLabors.ImageSharp private static ReadOnlySpan PermuteMaskDeinterleave8x32 => new byte[] { 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0 }; /// - /// as many elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + internal static void NormalizedFloatToByteSaturateReduce( ref ReadOnlySpan source, ref Span dest) { @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp if (adjustedCount > 0) { - BulkConvertNormalizedFloatToByteClampOverflows( + NormalizedFloatToByteSaturate( source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); @@ -46,13 +46,13 @@ namespace SixLabors.ImageSharp } /// - /// Implementation of , which is faster on new .NET runtime. + /// Implementation of , which is faster on new .NET runtime. /// /// /// Implementation is based on MagicScaler code: /// https://github.com/saucecontrol/PhotoSauce/blob/a9bd6e5162d2160419f0cf743fd4f536c079170b/src/MagicScaler/Magic/Processors/ConvertersFloat.cs#L453-L477 /// - internal static void BulkConvertNormalizedFloatToByteClampOverflows( + internal static void NormalizedFloatToByteSaturate( ReadOnlySpan source, Span dest) { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index ba3d9c4e83..1099678f76 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -21,10 +21,10 @@ namespace SixLabors.ImageSharp #if !SUPPORTS_EXTENDED_INTRINSICS /// - /// as many elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertByteToNormalizedFloatReduce( + internal static void ByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp if (adjustedCount > 0) { - BulkConvertByteToNormalizedFloat( + ByteToNormalizedFloat( source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); @@ -50,10 +50,10 @@ namespace SixLabors.ImageSharp } /// - /// as many elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + internal static void NormalizedFloatToByteSaturateReduce( ref ReadOnlySpan source, ref Span dest) { @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp if (adjustedCount > 0) { - BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); + NormalizedFloatToByteSaturate(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); source = source.Slice(adjustedCount); dest = dest.Slice(adjustedCount); @@ -78,15 +78,15 @@ namespace SixLabors.ImageSharp #endif /// - /// SIMD optimized implementation for . + /// SIMD optimized implementation for . /// Works only with span Length divisible by 8. /// Implementation adapted from: /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions /// http://stackoverflow.com/a/536278 /// - internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - VerifyHasVector8(nameof(BulkConvertByteToNormalizedFloat)); + VerifyHasVector8(nameof(ByteToNormalizedFloat)); VerifySpanInput(source, dest, 8); var bVec = new Vector(256.0f / 255.0f); @@ -124,11 +124,11 @@ namespace SixLabors.ImageSharp } /// - /// Implementation of which is faster on older runtimes. + /// Implementation of which is faster on older runtimes. /// - internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span dest) { - VerifyHasVector8(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); + VerifyHasVector8(nameof(NormalizedFloatToByteSaturate)); VerifySpanInput(source, dest, 8); if (source.Length == 0) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 7baa788e41..69d5dfa73a 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -43,10 +43,10 @@ namespace SixLabors.ImageSharp } /// - /// as many elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertByteToNormalizedFloatReduce( + internal static void ByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp if (adjustedCount > 0) { - BulkConvertByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); + ByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); source = source.Slice(adjustedCount); dest = dest.Slice(adjustedCount); @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp } /// - /// as many elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + internal static void NormalizedFloatToByteSaturateReduce( ref ReadOnlySpan source, ref Span dest) { @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp if (adjustedCount > 0) { - BulkConvertNormalizedFloatToByteClampOverflows( + NormalizedFloatToByteSaturate( source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); @@ -99,9 +99,9 @@ namespace SixLabors.ImageSharp } /// - /// Implementation , which is faster on new RyuJIT runtime. + /// Implementation , which is faster on new RyuJIT runtime. /// - internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) { VerifySpanInput(source, dest, Vector.Count); @@ -132,9 +132,9 @@ namespace SixLabors.ImageSharp } /// - /// Implementation of , which is faster on new .NET runtime. + /// Implementation of , which is faster on new .NET runtime. /// - internal static void BulkConvertNormalizedFloatToByteClampOverflows( + internal static void NormalizedFloatToByteSaturate( ReadOnlySpan source, Span dest) { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index 565ea08f5d..aaacfdd85c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -19,10 +19,10 @@ namespace SixLabors.ImageSharp public static class FallbackIntrinsics128 { /// - /// as many elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertByteToNormalizedFloatReduce( + internal static void ByteToNormalizedFloatReduce( ref ReadOnlySpan source, ref Span dest) { @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp if (adjustedCount > 0) { - BulkConvertByteToNormalizedFloat( + ByteToNormalizedFloat( source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); @@ -43,10 +43,10 @@ namespace SixLabors.ImageSharp } /// - /// as many elements as possible, slicing them down (keeping the remainder). + /// as many elements as possible, slicing them down (keeping the remainder). /// [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + internal static void NormalizedFloatToByteSaturateReduce( ref ReadOnlySpan source, ref Span dest) { @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp if (adjustedCount > 0) { - BulkConvertNormalizedFloatToByteClampOverflows( + NormalizedFloatToByteSaturate( source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); @@ -67,10 +67,10 @@ namespace SixLabors.ImageSharp } /// - /// Implementation of using . + /// Implementation of using . /// [MethodImpl(InliningOptions.ColdPath)] - internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) { VerifySpanInput(source, dest, 4); @@ -99,10 +99,10 @@ namespace SixLabors.ImageSharp } /// - /// Implementation of using . + /// Implementation of using . /// [MethodImpl(InliningOptions.ColdPath)] - internal static void BulkConvertNormalizedFloatToByteClampOverflows( + internal static void NormalizedFloatToByteSaturate( ReadOnlySpan source, Span dest) { @@ -148,4 +148,4 @@ namespace SixLabors.ImageSharp } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index de313c8d57..b58ec900f3 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -61,16 +61,18 @@ namespace SixLabors.ImageSharp /// The source span of bytes /// The destination span of floats [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); #if SUPPORTS_EXTENDED_INTRINSICS - ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + ExtendedIntrinsics.ByteToNormalizedFloatReduce(ref source, ref dest); #else - BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + BasicIntrinsics256.ByteToNormalizedFloatReduce(ref source, ref dest); #endif - FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + + // Also deals with the remainder from previous conversions: + FallbackIntrinsics128.ByteToNormalizedFloatReduce(ref source, ref dest); // Deal with the remainder: if (source.Length > 0) @@ -88,20 +90,20 @@ namespace SixLabors.ImageSharp /// The source span of floats /// The destination span of bytes [MethodImpl(InliningOptions.ShortMethod)] - internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span dest) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); #if SUPPORTS_RUNTIME_INTRINSICS - Avx2Intrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + Avx2Intrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref dest); #elif SUPPORTS_EXTENDED_INTRINSICS - ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + ExtendedIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref dest); #else - BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + BasicIntrinsics256.NormalizedFloatToByteSaturateReduce(ref source, ref dest); #endif // Also deals with the remainder from previous conversions: - FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + FallbackIntrinsics128.NormalizedFloatToByteSaturateReduce(ref source, ref dest); // Deal with the remainder: if (source.Length > 0) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 7337c0c895..0b0e9b1c18 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.PixelFormats Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationVectors, nameof(destinationVectors)); destinationVectors = destinationVectors.Slice(0, sourcePixels.Length); - SimdUtils.BulkConvertByteToNormalizedFloat( + SimdUtils.ByteToNormalizedFloat( MemoryMarshal.Cast(sourcePixels), MemoryMarshal.Cast(destinationVectors)); Vector4Converters.ApplyForwardConversionModifiers(destinationVectors, modifiers); @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.PixelFormats destinationPixels = destinationPixels.Slice(0, sourceVectors.Length); Vector4Converters.ApplyBackwardConversionModifiers(sourceVectors, modifiers); - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + SimdUtils.NormalizedFloatToByteSaturate( MemoryMarshal.Cast(sourceVectors), MemoryMarshal.Cast(destinationPixels)); } diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index af04a06b7b..4ee645c207 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers, // but we are always reading/writing at different positions: - SimdUtils.BulkConvertByteToNormalizedFloat( + SimdUtils.ByteToNormalizedFloat( MemoryMarshal.Cast(lastQuarterOfDestBuffer), MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils { Span tempSpan = tempBuffer.Memory.Span; - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + SimdUtils.NormalizedFloatToByteSaturate( MemoryMarshal.Cast(sourceVectors), MemoryMarshal.Cast(tempSpan)); diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index ef554a0110..b6bfca4b53 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Tests.Common { TestImpl_BulkConvertByteToNormalizedFloat( count, - (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + (s, d) => SimdUtils.FallbackIntrinsics128.ByteToNormalizedFloat(s.Span, d.Span)); } [Theory] @@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp.Tests.Common TestImpl_BulkConvertByteToNormalizedFloat( count, - (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + (s, d) => SimdUtils.BasicIntrinsics256.ByteToNormalizedFloat(s.Span, d.Span)); } [Theory] @@ -201,7 +201,7 @@ namespace SixLabors.ImageSharp.Tests.Common { TestImpl_BulkConvertByteToNormalizedFloat( count, - (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + (s, d) => SimdUtils.ExtendedIntrinsics.ByteToNormalizedFloat(s.Span, d.Span)); } [Theory] @@ -210,7 +210,7 @@ namespace SixLabors.ImageSharp.Tests.Common { TestImpl_BulkConvertByteToNormalizedFloat( count, - (s, d) => SimdUtils.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + (s, d) => SimdUtils.ByteToNormalizedFloat(s.Span, d.Span)); } private static void TestImpl_BulkConvertByteToNormalizedFloat( @@ -232,7 +232,7 @@ namespace SixLabors.ImageSharp.Tests.Common { TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( count, - (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span)); + (s, d) => SimdUtils.FallbackIntrinsics128.NormalizedFloatToByteSaturate(s.Span, d.Span)); } [Theory] @@ -244,7 +244,7 @@ namespace SixLabors.ImageSharp.Tests.Common return; } - TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span)); + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.BasicIntrinsics256.NormalizedFloatToByteSaturate(s.Span, d.Span)); } [Theory] @@ -253,7 +253,7 @@ namespace SixLabors.ImageSharp.Tests.Common { TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( count, - (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span)); + (s, d) => SimdUtils.ExtendedIntrinsics.NormalizedFloatToByteSaturate(s.Span, d.Span)); } [Theory] @@ -290,7 +290,7 @@ namespace SixLabors.ImageSharp.Tests.Common TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( count, - (s, d) => SimdUtils.Avx2Intrinsics.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span)); + (s, d) => SimdUtils.Avx2Intrinsics.NormalizedFloatToByteSaturate(s.Span, d.Span)); } #endif @@ -299,7 +299,7 @@ namespace SixLabors.ImageSharp.Tests.Common [MemberData(nameof(ArbitraryArraySizes))] public void BulkConvertNormalizedFloatToByteClampOverflows(int count) { - TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span)); + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, (s, d) => SimdUtils.NormalizedFloatToByteSaturate(s.Span, d.Span)); // For small values, let's stress test the implementation a bit: if (count > 0 && count < 10) @@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.Tests.Common { TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( count, - (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span), + (s, d) => SimdUtils.NormalizedFloatToByteSaturate(s.Span, d.Span), i + 42); } } From c567762368867873259a37960dadb8a8b335a255 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 12 Mar 2020 23:02:43 +0100 Subject: [PATCH 054/213] fix GetSingleSpan() & GetSingleMemory() --- src/ImageSharp/Memory/Buffer2D{T}.cs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 16b3b90630..bf8630931a 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.Memory internal Span GetSingleSpan() { // TODO: If we need a public version of this method, we need to cache the non-fast Memory of this.MemoryGroup - return this.cachedMemory.Length != 0 ? this.cachedMemory.Span : ThrowInvalidOperationSingleSpan(); + return this.cachedMemory.Length != 0 ? this.cachedMemory.Span : this.GetSingleSpanSlow(); } /// @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp.Memory internal Memory GetSingleMemory() { // TODO: If we need a public version of this method, we need to cache the non-fast Memory of this.MemoryGroup - return this.cachedMemory.Length != 0 ? this.cachedMemory : ThrowInvalidOperationSingleMemory(); + return this.cachedMemory.Length != 0 ? this.cachedMemory : this.GetSingleMemorySlow(); } /// @@ -205,6 +205,9 @@ namespace SixLabors.ImageSharp.Memory [MethodImpl(InliningOptions.ColdPath)] private Memory GetSingleMemorySlow() => this.FastMemoryGroup.Single(); + [MethodImpl(InliningOptions.ColdPath)] + private Span GetSingleSpanSlow() => this.FastMemoryGroup.Single().Span; + [MethodImpl(InliningOptions.ColdPath)] private ref T GetElementSlow(int x, int y) { @@ -230,17 +233,5 @@ namespace SixLabors.ImageSharp.Memory b.cachedMemory = aCached; } } - - [MethodImpl(InliningOptions.ColdPath)] - private static Memory ThrowInvalidOperationSingleMemory() - { - throw new InvalidOperationException("GetSingleMemory is only valid for a single-buffer group!"); - } - - [MethodImpl(InliningOptions.ColdPath)] - private static Span ThrowInvalidOperationSingleSpan() - { - throw new InvalidOperationException("GetSingleSpan is only valid for a single-buffer group!"); - } } } From 16afcab5440a265590c3f8e680f5b4d2941d4141 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 12 Mar 2020 23:23:32 +0100 Subject: [PATCH 055/213] tweak tolerance for DetectEdgesTest and OilPaintTest --- .../Processors/Convolution/DetectEdgesTest.cs | 23 +++++++++++++------ .../Processors/Effects/OilPaintTest.cs | 13 +++++++---- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs index b324b745cc..3d1e378b16 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs @@ -12,9 +12,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution [GroupOutput("Convolution")] public class DetectEdgesTest { - // I think our comparison is not accurate enough (nor can be) for RgbaVector. - // The image pixels are identical according to BeyondCompare. - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0456F); + private static readonly ImageComparer OpaqueComparer = ImageComparer.TolerantPercentage(0.01F); + + private static readonly ImageComparer TransparentComparer = ImageComparer.TolerantPercentage(0.5F); public static readonly string[] TestImages = { Tests.TestImages.Png.Bike }; @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution var bounds = new Rectangle(10, 10, size.Width / 2, size.Height / 2); ctx.DetectEdges(bounds); }, - comparer: ValidatorComparer, + comparer: OpaqueComparer, useReferenceOutputFrom: nameof(this.DetectEdges_InBox)); } @@ -56,11 +56,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution public void DetectEdges_WorksWithAllFilters(TestImageProvider provider, EdgeDetectionOperators detector) where TPixel : unmanaged, IPixel { + bool hasAlpha = provider.SourceFileOrDescription.Contains("TestPattern"); + ImageComparer comparer = hasAlpha ? TransparentComparer : OpaqueComparer; using (Image image = provider.GetImage()) { image.Mutate(x => x.DetectEdges(detector)); image.DebugSave(provider, detector.ToString()); - image.CompareToReferenceOutput(ValidatorComparer, provider, detector.ToString()); + image.CompareToReferenceOutput(comparer, provider, detector.ToString()); } } @@ -69,11 +71,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution public void DetectEdges_IsNotBoundToSinglePixelType(TestImageProvider provider) where TPixel : unmanaged, IPixel { + // James: + // I think our comparison is not accurate enough (nor can be) for RgbaVector. + // The image pixels are identical according to BeyondCompare. + ImageComparer comparer = typeof(TPixel) == typeof(RgbaVector) ? + ImageComparer.TolerantPercentage(1f) : + OpaqueComparer; + using (Image image = provider.GetImage()) { image.Mutate(x => x.DetectEdges()); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(comparer, provider); } } @@ -100,7 +109,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution image.Mutate(x => x.DetectEdges(bounds)); image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); + image.CompareToReferenceOutput(OpaqueComparer, provider); } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Effects/OilPaintTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Effects/OilPaintTest.cs index 7070e555ab..4eeebc3a0c 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Effects/OilPaintTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Effects/OilPaintTest.cs @@ -3,7 +3,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; - +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Effects @@ -29,8 +29,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Effects where TPixel : unmanaged, IPixel { provider.RunValidatingProcessorTest( - x => x.OilPaint(levels, brushSize), - $"{levels}-{brushSize}", + x => + { + x.OilPaint(levels, brushSize); + return $"{levels}-{brushSize}"; + }, + ImageComparer.TolerantPercentage(0.01F), appendPixelTypeToFileName: false); } @@ -42,7 +46,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Effects { provider.RunRectangleConstrainedValidatingProcessorTest( (x, rect) => x.OilPaint(levels, brushSize, rect), - $"{levels}-{brushSize}"); + $"{levels}-{brushSize}", + ImageComparer.TolerantPercentage(0.01F)); } } } From 939c16455a30f49def3c9ed526905c1cc2097800 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 12 Mar 2020 23:36:34 +0100 Subject: [PATCH 056/213] disable EntropyCrop test on .NET Core 3.1 for ducky.png --- .../Processors/Transforms/EntropyCropTest.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs index a9b982cf83..5b0952f30d 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using Xunit; @@ -24,7 +25,16 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public void EntropyCrop(TestImageProvider provider, float value) where TPixel : unmanaged, IPixel { + // The result dimensions of EntropyCrop may differ on .NET Core 3.1 because of unstable edge detection results. + // TODO: Re-enable this test case if we manage to improve stability. +#if SUPPORTS_RUNTIME_INTRINSICS + if (provider.SourceFileOrDescription.Contains(TestImages.Png.Ducky)) + { + return; + } +#endif + provider.RunValidatingProcessorTest(x => x.EntropyCrop(value), value, appendPixelTypeToFileName: false); } } -} \ No newline at end of file +} From 26ddbc06d39e52c80a38baab740cc53af6b77224 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 12 Mar 2020 23:49:49 +0100 Subject: [PATCH 057/213] on Framework, SkipAllQuantizerTests should be also true locally --- .../Processing/Processors/Quantization/QuantizerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs index 4ea01c94ce..bcbb60e798 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization /// Not worth investigating for now. /// /// - private static readonly bool SkipAllQuantizerTests = TestEnvironment.RunsOnCI && TestEnvironment.IsFramework; + private static readonly bool SkipAllQuantizerTests = TestEnvironment.IsFramework; public static readonly string[] CommonTestImages = { From 810d3bbe04911534cec95c523e60ae7435cd4c8b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 13 Mar 2020 00:03:28 +0100 Subject: [PATCH 058/213] fix Benchmarks build --- tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs | 8 ++++---- .../ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 73c9116fd4..1184bef2e0 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + SimdUtils.FallbackIntrinsics128.NormalizedFloatToByteSaturate(sBytes, dFloats); } [Benchmark] @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + SimdUtils.BasicIntrinsics256.NormalizedFloatToByteSaturate(sBytes, dFloats); } [Benchmark(Baseline = true)] @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + SimdUtils.ExtendedIntrinsics.NormalizedFloatToByteSaturate(sBytes, dFloats); } #if SUPPORTS_RUNTIME_INTRINSICS @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.Avx2Intrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + SimdUtils.Avx2Intrinsics.NormalizedFloatToByteSaturate(sBytes, dFloats); } private static ReadOnlySpan PermuteMaskDeinterleave8x32 => new byte[] { 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0 }; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs index b74a412c8f..483ab61741 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + SimdUtils.FallbackIntrinsics128.ByteToNormalizedFloat(sBytes, dFloats); } [Benchmark] @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + SimdUtils.BasicIntrinsics256.ByteToNormalizedFloat(sBytes, dFloats); } [Benchmark] @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + SimdUtils.ExtendedIntrinsics.ByteToNormalizedFloat(sBytes, dFloats); } // [Benchmark] From e7e30bc258652ff7fff10b06457276f0243bff60 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 14 Mar 2020 17:54:17 +1100 Subject: [PATCH 059/213] Fix edge detection and reenable entropy crop tests --- .../ConvolutionProcessor{TPixel}.cs | 6 +- .../EdgeDetector2DProcessor{TPixel}.cs | 5 ++ .../EdgeDetectorCompassProcessor{TPixel}.cs | 5 ++ .../EdgeDetectorProcessor{TPixel}.cs | 5 ++ .../Filters/OpaqueProcessor{TPixel}.cs | 67 +++++++++++++++++++ .../Processors/Transforms/EntropyCropTest.cs | 11 +-- tests/Images/External | 2 +- 7 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index a2c8fc1fbe..8201b8e239 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -58,9 +58,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var operation = new RowOperation(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha); ParallelRowIterator.IterateRows( - this.Configuration, - interest, - in operation); + this.Configuration, + interest, + in operation); Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs index bdcf3cbc09..8bb60286a7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs @@ -52,6 +52,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void BeforeImageApply() { + using (IImageProcessor opaque = new OpaqueProcessor(this.Configuration, this.Source, this.SourceRectangle)) + { + opaque.Execute(); + } + if (this.Grayscale) { new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle); diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index 159c67b5cf..1b07589b51 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -40,6 +40,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void BeforeImageApply() { + using (IImageProcessor opaque = new OpaqueProcessor(this.Configuration, this.Source, this.SourceRectangle)) + { + opaque.Execute(); + } + if (this.Grayscale) { new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle); diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs index c49d03eb5c..8ca548d975 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs @@ -43,6 +43,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void BeforeImageApply() { + using (IImageProcessor opaque = new OpaqueProcessor(this.Configuration, this.Source, this.SourceRectangle)) + { + opaque.Execute(); + } + if (this.Grayscale) { new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle); diff --git a/src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs new file mode 100644 index 0000000000..95a099106f --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs @@ -0,0 +1,67 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Filters +{ + internal sealed class OpaqueProcessor : ImageProcessor + where TPixel : unmanaged, IPixel + { + public OpaqueProcessor( + Configuration configuration, + Image source, + Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) + { + } + + protected override void OnFrameApply(ImageFrame source) + { + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); + + var operation = new OpaqueRowOperation(this.Configuration, source, interest); + ParallelRowIterator.IterateRows(this.Configuration, interest, in operation); + } + + private readonly struct OpaqueRowOperation : IRowOperation + { + private readonly Configuration configuration; + private readonly ImageFrame target; + private readonly Rectangle bounds; + + [MethodImpl(InliningOptions.ShortMethod)] + public OpaqueRowOperation( + Configuration configuration, + ImageFrame target, + Rectangle bounds) + { + this.configuration = configuration; + this.target = target; + this.bounds = bounds; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void Invoke(int y, Span span) + { + Span targetRowSpan = this.target.GetPixelRowSpan(y).Slice(this.bounds.X); + PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span, PixelConversionModifiers.Scale); + ref Vector4 baseRef = ref MemoryMarshal.GetReference(span); + + for (int x = 0; x < this.bounds.Width; x++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, x); + v.W = 1F; + } + + PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan, PixelConversionModifiers.Scale); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs index 5b0952f30d..a04aef6bca 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -25,15 +25,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public void EntropyCrop(TestImageProvider provider, float value) where TPixel : unmanaged, IPixel { - // The result dimensions of EntropyCrop may differ on .NET Core 3.1 because of unstable edge detection results. - // TODO: Re-enable this test case if we manage to improve stability. -#if SUPPORTS_RUNTIME_INTRINSICS - if (provider.SourceFileOrDescription.Contains(TestImages.Png.Ducky)) - { - return; - } -#endif - provider.RunValidatingProcessorTest(x => x.EntropyCrop(value), value, appendPixelTypeToFileName: false); } } diff --git a/tests/Images/External b/tests/Images/External index 1fea1ceab8..d809551931 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 1fea1ceab89e87cc5f11376fa46164d3d27566c0 +Subproject commit d809551931858cd3873bad49d2fe915fddff7a26 From 29b709da12e3d23f9efb132dc83ca74216fb8c06 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 14 Mar 2020 23:28:12 +1100 Subject: [PATCH 060/213] Add overloads. Fix #1144 --- src/ImageSharp/Image.FromBytes.cs | 40 ++++++++ src/ImageSharp/Image.FromFile.cs | 42 +++++++- src/ImageSharp/Image.FromStream.cs | 4 +- .../Image/ImageTests.Identify.cs | 99 +++++++++++++++++++ .../Image/ImageTests.ImageLoadTestBase.cs | 11 ++- 5 files changed, 189 insertions(+), 7 deletions(-) create mode 100644 tests/ImageSharp.Tests/Image/ImageTests.Identify.cs diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 0850e2213f..f1196ac977 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -37,6 +37,46 @@ namespace SixLabors.ImageSharp } } + /// + /// Reads the raw image information from the specified stream without fully decoding it. + /// + /// The byte array containing encoded image data to read the header from. + /// Thrown if the stream is not readable. + /// + /// The or null if suitable info detector not found. + /// + public static IImageInfo Identify(byte[] data) => Identify(data, out IImageFormat _); + + /// + /// Reads the raw image information from the specified stream without fully decoding it. + /// + /// The byte array containing encoded image data to read the header from. + /// The format type of the decoded image. + /// Thrown if the stream is not readable. + /// + /// The or null if suitable info detector not found. + /// + public static IImageInfo Identify(byte[] data, out IImageFormat format) => Identify(Configuration.Default, data, out format); + + /// + /// Reads the raw image information from the specified stream without fully decoding it. + /// + /// The configuration. + /// The byte array containing encoded image data to read the header from. + /// The format type of the decoded image. + /// Thrown if the stream is not readable. + /// + /// The or null if suitable info detector is not found. + /// + public static IImageInfo Identify(Configuration config, byte[] data, out IImageFormat format) + { + config ??= Configuration.Default; + using (var stream = new MemoryStream(data)) + { + return Identify(config, stream, out format); + } + } + /// /// Load a new instance of from the given encoded byte array. /// diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index 45ea378cfd..bb26e4142c 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -31,13 +31,53 @@ namespace SixLabors.ImageSharp /// The mime type or null if none found. public static IImageFormat DetectFormat(Configuration config, string filePath) { - config = config ?? Configuration.Default; + config ??= Configuration.Default; using (Stream file = config.FileSystem.OpenRead(filePath)) { return DetectFormat(config, file); } } + /// + /// Reads the raw image information from the specified stream without fully decoding it. + /// + /// The image file to open and to read the header from. + /// Thrown if the stream is not readable. + /// + /// The or null if suitable info detector not found. + /// + public static IImageInfo Identify(string filePath) => Identify(filePath, out IImageFormat _); + + /// + /// Reads the raw image information from the specified stream without fully decoding it. + /// + /// The image file to open and to read the header from. + /// The format type of the decoded image. + /// Thrown if the stream is not readable. + /// + /// The or null if suitable info detector not found. + /// + public static IImageInfo Identify(string filePath, out IImageFormat format) => Identify(Configuration.Default, filePath, out format); + + /// + /// Reads the raw image information from the specified stream without fully decoding it. + /// + /// The configuration. + /// The image file to open and to read the header from. + /// The format type of the decoded image. + /// Thrown if the stream is not readable. + /// + /// The or null if suitable info detector is not found. + /// + public static IImageInfo Identify(Configuration config, string filePath, out IImageFormat format) + { + config ??= Configuration.Default; + using (Stream file = config.FileSystem.OpenRead(filePath)) + { + return Identify(config, file, out format); + } + } + /// /// Create a new instance of the class from the given file. /// diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index d756ff7ac1..95a71903a8 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp => WithSeekableStream(config, stream, s => InternalDetectFormat(s, config)); /// - /// By reading the header on the provided stream this reads the raw image information. + /// Reads the raw image information from the specified stream without fully decoding it. /// /// The image stream to read the header from. /// Thrown if the stream is not readable. @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp public static IImageInfo Identify(Stream stream) => Identify(stream, out IImageFormat _); /// - /// By reading the header on the provided stream this reads the raw image information. + /// Reads the raw image information from the specified stream without fully decoding it. /// /// The image stream to read the header from. /// The format type of the decoded image. diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs new file mode 100644 index 0000000000..2be9504079 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs @@ -0,0 +1,99 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; +using SixLabors.ImageSharp.Formats; + +using Xunit; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests +{ + public partial class ImageTests + { + /// + /// Tests the class. + /// + public class Identify : ImageLoadTestBase + { + private static readonly string ActualImagePath = TestFile.GetInputFileFullPath(TestImages.Bmp.F); + + private byte[] ActualImageBytes => TestFile.Create(TestImages.Bmp.F).Bytes; + + private byte[] ByteArray => this.DataStream.ToArray(); + + private IImageInfo LocalImageInfo => this.localImageInfoMock.Object; + + private IImageFormat LocalImageFormat => this.localImageFormatMock.Object; + + private static readonly IImageFormat ExpectedGlobalFormat = + Configuration.Default.ImageFormatsManager.FindFormatByFileExtension("bmp"); + + [Fact] + public void FromBytes_GlobalConfiguration() + { + IImageInfo info = Image.Identify(this.ActualImageBytes, out IImageFormat type); + + Assert.NotNull(info); + Assert.Equal(ExpectedGlobalFormat, type); + } + + [Fact] + public void FromBytes_CustomConfiguration() + { + IImageInfo info = Image.Identify(this.LocalConfiguration, this.ByteArray, out IImageFormat type); + + Assert.Equal(this.LocalImageInfo, info); + Assert.Equal(this.LocalImageFormat, type); + } + + [Fact] + public void FromFileSystemPath_GlobalConfiguration() + { + IImageInfo info = Image.Identify(ActualImagePath, out IImageFormat type); + + Assert.NotNull(info); + Assert.Equal(ExpectedGlobalFormat, type); + } + + [Fact] + public void FromFileSystemPath_CustomConfiguration() + { + IImageInfo info = Image.Identify(this.LocalConfiguration, this.MockFilePath, out IImageFormat type); + + Assert.Equal(this.LocalImageInfo, info); + Assert.Equal(this.LocalImageFormat, type); + } + + [Fact] + public void FromStream_GlobalConfiguration() + { + using (var stream = new MemoryStream(this.ActualImageBytes)) + { + IImageInfo info = Image.Identify(stream, out IImageFormat type); + + Assert.NotNull(info); + Assert.Equal(ExpectedGlobalFormat, type); + } + } + + [Fact] + public void FromStream_CustomConfiguration() + { + IImageInfo info = Image.Identify(this.LocalConfiguration, this.DataStream, out IImageFormat type); + + Assert.Equal(this.LocalImageInfo, info); + Assert.Equal(this.LocalImageFormat, type); + } + + [Fact] + public void WhenNoMatchingFormatFound_ReturnsNull() + { + IImageInfo info = Image.Identify(new Configuration(), this.DataStream, out IImageFormat type); + + Assert.Null(info); + Assert.Null(type); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs index dff83df26d..d010f60236 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs @@ -26,6 +26,8 @@ namespace SixLabors.ImageSharp.Tests protected Mock localImageFormatMock; + protected Mock localImageInfoMock; + protected readonly string MockFilePath = Guid.NewGuid().ToString(); internal readonly Mock LocalFileSystemMock = new Mock(); @@ -53,9 +55,12 @@ namespace SixLabors.ImageSharp.Tests this.localStreamReturnImageRgba32 = new Image(1, 1); this.localStreamReturnImageAgnostic = new Image(1, 1); + this.localImageInfoMock = new Mock(); this.localImageFormatMock = new Mock(); - this.localDecoder = new Mock(); + var detector = new Mock(); + detector.Setup(x => x.Identify(It.IsAny(), It.IsAny())).Returns(this.localImageInfoMock.Object); + this.localDecoder = detector.As(); this.localMimeTypeDetector = new MockImageFormatDetector(this.localImageFormatMock.Object); this.localDecoder.Setup(x => x.Decode(It.IsAny(), It.IsAny())) @@ -80,9 +85,7 @@ namespace SixLabors.ImageSharp.Tests }) .Returns(this.localStreamReturnImageAgnostic); - this.LocalConfiguration = new Configuration - { - }; + this.LocalConfiguration = new Configuration(); this.LocalConfiguration.ImageFormatsManager.AddImageFormatDetector(this.localMimeTypeDetector); this.LocalConfiguration.ImageFormatsManager.SetDecoder(this.localImageFormatMock.Object, this.localDecoder.Object); From 0873fe52446b7dd9f4d466d0727c340729afcd97 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 15 Mar 2020 00:29:54 +1100 Subject: [PATCH 061/213] Add Guard checks, don't pass null, --- src/ImageSharp/Image.FromBytes.cs | 95 +++++++++++++++--------------- src/ImageSharp/Image.FromFile.cs | 69 ++++++++++++---------- src/ImageSharp/Image.FromStream.cs | 64 ++++++++++---------- 3 files changed, 117 insertions(+), 111 deletions(-) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index f1196ac977..06b05fe3c4 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -26,14 +26,15 @@ namespace SixLabors.ImageSharp /// /// By reading the header on the provided byte array this calculates the images format. /// - /// The configuration. + /// The configuration. /// The byte array containing encoded image data to read the header from. /// The mime type or null if none found. - public static IImageFormat DetectFormat(Configuration config, byte[] data) + public static IImageFormat DetectFormat(Configuration configuration, byte[] data) { - using (var stream = new MemoryStream(data)) + Guard.NotNull(configuration, nameof(configuration)); + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return DetectFormat(config, stream); + return DetectFormat(configuration, stream); } } @@ -61,19 +62,19 @@ namespace SixLabors.ImageSharp /// /// Reads the raw image information from the specified stream without fully decoding it. /// - /// The configuration. + /// The configuration. /// The byte array containing encoded image data to read the header from. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// /// The or null if suitable info detector is not found. /// - public static IImageInfo Identify(Configuration config, byte[] data, out IImageFormat format) + public static IImageInfo Identify(Configuration configuration, byte[] data, out IImageFormat format) { - config ??= Configuration.Default; - using (var stream = new MemoryStream(data)) + Guard.NotNull(configuration, nameof(configuration)); + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return Identify(config, stream, out format); + return Identify(configuration, stream, out format); } } @@ -108,33 +109,33 @@ namespace SixLabors.ImageSharp /// /// Load a new instance of from the given encoded byte array. /// - /// The configuration options. + /// The configuration options. /// The byte array containing encoded image data. /// The pixel format. /// A new . - public static Image Load(Configuration config, byte[] data) + public static Image Load(Configuration configuration, byte[] data) where TPixel : unmanaged, IPixel { using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return Load(config, stream); + return Load(configuration, stream); } } /// /// Load a new instance of from the given encoded byte array. /// - /// The configuration options. + /// The configuration options. /// The byte array containing encoded image data. /// The of the decoded image. /// The pixel format. /// A new . - public static Image Load(Configuration config, byte[] data, out IImageFormat format) + public static Image Load(Configuration configuration, byte[] data, out IImageFormat format) where TPixel : unmanaged, IPixel { using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return Load(config, stream, out format); + return Load(configuration, stream, out format); } } @@ -157,17 +158,17 @@ namespace SixLabors.ImageSharp /// /// Load a new instance of from the given encoded byte array. /// - /// The Configuration. + /// The Configuration. /// The byte array containing encoded image data. /// The decoder. /// The pixel format. /// A new . - public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) + public static Image Load(Configuration configuration, byte[] data, IImageDecoder decoder) where TPixel : unmanaged, IPixel { using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return Load(config, stream, decoder); + return Load(configuration, stream, decoder); } } @@ -184,18 +185,18 @@ namespace SixLabors.ImageSharp /// /// By reading the header on the provided byte array this calculates the images format. /// - /// The configuration. + /// The configuration. /// The byte array containing encoded image data to read the header from. /// The mime type or null if none found. - public static IImageFormat DetectFormat(Configuration config, ReadOnlySpan data) + public static IImageFormat DetectFormat(Configuration configuration, ReadOnlySpan data) { - int maxHeaderSize = config.MaxHeaderSize; + int maxHeaderSize = configuration.MaxHeaderSize; if (maxHeaderSize <= 0) { return null; } - foreach (IImageFormatDetector detector in config.ImageFormatsManager.FormatDetectors) + foreach (IImageFormatDetector detector in configuration.ImageFormatsManager.FormatDetectors) { IImageFormat f = detector.DetectFormat(data); @@ -243,18 +244,18 @@ namespace SixLabors.ImageSharp /// /// Load a new instance of from the given encoded byte span. /// - /// The configuration options. + /// The configuration options. /// The byte span containing encoded image data. /// The pixel format. /// A new . - public static unsafe Image Load(Configuration config, ReadOnlySpan data) + public static unsafe Image Load(Configuration configuration, ReadOnlySpan data) where TPixel : unmanaged, IPixel { fixed (byte* ptr = &data.GetPinnableReference()) { using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) { - return Load(config, stream); + return Load(configuration, stream); } } } @@ -262,13 +263,13 @@ namespace SixLabors.ImageSharp /// /// Load a new instance of from the given encoded byte span. /// - /// The Configuration. + /// The Configuration. /// The byte span containing image data. /// The decoder. /// The pixel format. /// A new . public static unsafe Image Load( - Configuration config, + Configuration configuration, ReadOnlySpan data, IImageDecoder decoder) where TPixel : unmanaged, IPixel @@ -277,7 +278,7 @@ namespace SixLabors.ImageSharp { using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) { - return Load(config, stream, decoder); + return Load(configuration, stream, decoder); } } } @@ -285,13 +286,13 @@ namespace SixLabors.ImageSharp /// /// Load a new instance of from the given encoded byte span. /// - /// The configuration options. + /// The configuration options. /// The byte span containing image data. /// The of the decoded image. /// The pixel format. /// A new . public static unsafe Image Load( - Configuration config, + Configuration configuration, ReadOnlySpan data, out IImageFormat format) where TPixel : unmanaged, IPixel @@ -300,7 +301,7 @@ namespace SixLabors.ImageSharp { using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) { - return Load(config, stream, out format); + return Load(configuration, stream, out format); } } } @@ -325,38 +326,38 @@ namespace SixLabors.ImageSharp /// /// Load a new instance of from the given encoded byte array. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The byte array containing encoded image data. /// The . - public static Image Load(Configuration config, byte[] data) => Load(config, data, out _); + public static Image Load(Configuration configuration, byte[] data) => Load(configuration, data, out _); /// /// Load a new instance of from the given encoded byte array. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The byte array containing image data. /// The decoder. /// The . - public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) + public static Image Load(Configuration configuration, byte[] data, IImageDecoder decoder) { using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return Load(config, stream, decoder); + return Load(configuration, stream, decoder); } } /// /// Load a new instance of from the given encoded byte array. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The byte array containing image data. /// The mime type of the decoded image. /// The . - public static Image Load(Configuration config, byte[] data, out IImageFormat format) + public static Image Load(Configuration configuration, byte[] data, out IImageFormat format) { using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return Load(config, stream, out format); + return Load(configuration, stream, out format); } } @@ -388,20 +389,20 @@ namespace SixLabors.ImageSharp /// /// Decodes a new instance of from the given encoded byte span. /// - /// The configuration options. + /// The configuration options. /// The byte span containing image data. /// The . - public static Image Load(Configuration config, ReadOnlySpan data) => Load(config, data, out _); + public static Image Load(Configuration configuration, ReadOnlySpan data) => Load(configuration, data, out _); /// /// Load a new instance of from the given encoded byte span. /// - /// The Configuration. + /// The Configuration. /// The byte span containing image data. /// The decoder. /// The . public static unsafe Image Load( - Configuration config, + Configuration configuration, ReadOnlySpan data, IImageDecoder decoder) { @@ -409,7 +410,7 @@ namespace SixLabors.ImageSharp { using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) { - return Load(config, stream, decoder); + return Load(configuration, stream, decoder); } } } @@ -417,12 +418,12 @@ namespace SixLabors.ImageSharp /// /// Load a new instance of from the given encoded byte span. /// - /// The configuration options. + /// The configuration options. /// The byte span containing image data. /// The of the decoded image.> /// The . public static unsafe Image Load( - Configuration config, + Configuration configuration, ReadOnlySpan data, out IImageFormat format) { @@ -430,7 +431,7 @@ namespace SixLabors.ImageSharp { using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) { - return Load(config, stream, out format); + return Load(configuration, stream, out format); } } } diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index bb26e4142c..1a9fa15462 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -26,15 +26,15 @@ namespace SixLabors.ImageSharp /// /// By reading the header on the provided file this calculates the images mime type. /// - /// The configuration. + /// The configuration. /// The image file to open and to read the header from. /// The mime type or null if none found. - public static IImageFormat DetectFormat(Configuration config, string filePath) + public static IImageFormat DetectFormat(Configuration configuration, string filePath) { - config ??= Configuration.Default; - using (Stream file = config.FileSystem.OpenRead(filePath)) + Guard.NotNull(configuration, nameof(configuration)); + using (Stream file = configuration.FileSystem.OpenRead(filePath)) { - return DetectFormat(config, file); + return DetectFormat(configuration, file); } } @@ -62,19 +62,19 @@ namespace SixLabors.ImageSharp /// /// Reads the raw image information from the specified stream without fully decoding it. /// - /// The configuration. + /// The configuration. /// The image file to open and to read the header from. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// /// The or null if suitable info detector is not found. /// - public static IImageInfo Identify(Configuration config, string filePath, out IImageFormat format) + public static IImageInfo Identify(Configuration configuration, string filePath, out IImageFormat format) { - config ??= Configuration.Default; - using (Stream file = config.FileSystem.OpenRead(filePath)) + Guard.NotNull(configuration, nameof(configuration)); + using (Stream file = configuration.FileSystem.OpenRead(filePath)) { - return Identify(config, file, out format); + return Identify(configuration, file, out format); } } @@ -102,29 +102,30 @@ namespace SixLabors.ImageSharp /// /// Create a new instance of the class from the given file. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The file path to the image. /// /// Thrown if the stream is not readable nor seekable. /// /// The . - public static Image Load(Configuration config, string path) => Load(config, path, out _); + public static Image Load(Configuration configuration, string path) => Load(configuration, path, out _); /// /// Create a new instance of the class from the given file. /// - /// The Configuration. + /// The Configuration. /// The file path to the image. /// The decoder. /// /// Thrown if the stream is not readable nor seekable. /// /// The . - public static Image Load(Configuration config, string path, IImageDecoder decoder) + public static Image Load(Configuration configuration, string path, IImageDecoder decoder) { - using (Stream stream = config.FileSystem.OpenRead(path)) + Guard.NotNull(configuration, nameof(configuration)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { - return Load(config, stream, decoder); + return Load(configuration, stream, decoder); } } @@ -173,26 +174,27 @@ namespace SixLabors.ImageSharp /// /// Create a new instance of the class from the given file. /// - /// The configuration options. + /// The configuration options. /// The file path to the image. /// /// Thrown if the stream is not readable nor seekable. /// /// The pixel format. /// A new . - public static Image Load(Configuration config, string path) + public static Image Load(Configuration configuration, string path) where TPixel : unmanaged, IPixel { - using (Stream stream = config.FileSystem.OpenRead(path)) + Guard.NotNull(configuration, nameof(configuration)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { - return Load(config, stream); + return Load(configuration, stream); } } /// /// Create a new instance of the class from the given file. /// - /// The configuration options. + /// The configuration options. /// The file path to the image. /// The mime type of the decoded image. /// @@ -200,12 +202,13 @@ namespace SixLabors.ImageSharp /// /// The pixel format. /// A new . - public static Image Load(Configuration config, string path, out IImageFormat format) + public static Image Load(Configuration configuration, string path, out IImageFormat format) where TPixel : unmanaged, IPixel { - using (Stream stream = config.FileSystem.OpenRead(path)) + Guard.NotNull(configuration, nameof(configuration)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { - return Load(config, stream, out format); + return Load(configuration, stream, out format); } } @@ -213,18 +216,19 @@ namespace SixLabors.ImageSharp /// Create a new instance of the class from the given file. /// The pixel type is selected by the decoder. /// - /// The configuration options. + /// The configuration options. /// The file path to the image. /// The mime type of the decoded image. /// /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(Configuration config, string path, out IImageFormat format) + public static Image Load(Configuration configuration, string path, out IImageFormat format) { - using (Stream stream = config.FileSystem.OpenRead(path)) + Guard.NotNull(configuration, nameof(configuration)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { - return Load(config, stream, out format); + return Load(configuration, stream, out format); } } @@ -247,7 +251,7 @@ namespace SixLabors.ImageSharp /// /// Create a new instance of the class from the given file. /// - /// The Configuration. + /// The Configuration. /// The file path to the image. /// The decoder. /// @@ -255,12 +259,13 @@ namespace SixLabors.ImageSharp /// /// The pixel format. /// A new . - public static Image Load(Configuration config, string path, IImageDecoder decoder) + public static Image Load(Configuration configuration, string path, IImageDecoder decoder) where TPixel : unmanaged, IPixel { - using (Stream stream = config.FileSystem.OpenRead(path)) + Guard.NotNull(configuration, nameof(configuration)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { - return Load(config, stream, decoder); + return Load(configuration, stream, decoder); } } } diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 95a71903a8..52d71409bb 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -26,12 +26,12 @@ namespace SixLabors.ImageSharp /// /// By reading the header on the provided stream this calculates the images format type. /// - /// The configuration. + /// The configuration. /// The image stream to read the header from. /// Thrown if the stream is not readable. /// The format type or null if none found. - public static IImageFormat DetectFormat(Configuration config, Stream stream) - => WithSeekableStream(config, stream, s => InternalDetectFormat(s, config)); + public static IImageFormat DetectFormat(Configuration configuration, Stream stream) + => WithSeekableStream(configuration, stream, s => InternalDetectFormat(s, configuration)); /// /// Reads the raw image information from the specified stream without fully decoding it. @@ -57,16 +57,16 @@ namespace SixLabors.ImageSharp /// /// Reads the raw image information from the specified stream without fully decoding it. /// - /// The configuration. + /// The configuration. /// The image stream to read the information from. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// /// The or null if suitable info detector is not found. /// - public static IImageInfo Identify(Configuration config, Stream stream, out IImageFormat format) + public static IImageInfo Identify(Configuration configuration, Stream stream, out IImageFormat format) { - (IImageInfo info, IImageFormat format) data = WithSeekableStream(config, stream, s => InternalIdentity(s, config ?? Configuration.Default)); + (IImageInfo info, IImageFormat format) data = WithSeekableStream(configuration, stream, s => InternalIdentity(s, configuration ?? Configuration.Default)); format = data.format; return data.info; @@ -108,24 +108,24 @@ namespace SixLabors.ImageSharp /// Decode a new instance of the class from the given stream. /// The pixel format is selected by the decoder. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The stream containing image information. /// The decoder. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// A new .> - public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) => - WithSeekableStream(config, stream, s => decoder.Decode(config, s)); + public static Image Load(Configuration configuration, Stream stream, IImageDecoder decoder) => + WithSeekableStream(configuration, stream, s => decoder.Decode(configuration, s)); /// /// Decode a new instance of the class from the given stream. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The stream containing image information. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// A new .> - public static Image Load(Configuration config, Stream stream) => Load(config, stream, out _); + public static Image Load(Configuration configuration, Stream stream) => Load(configuration, stream, out _); /// /// Create a new instance of the class from the given stream. @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp /// A new .> public static Image Load(Stream stream) where TPixel : unmanaged, IPixel - => Load(null, stream); + => Load(Configuration.Default, stream); /// /// Create a new instance of the class from the given stream. @@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp /// A new .> public static Image Load(Stream stream, out IImageFormat format) where TPixel : unmanaged, IPixel - => Load(null, stream, out format); + => Load(Configuration.Default, stream, out format); /// /// Create a new instance of the class from the given stream. @@ -168,45 +168,45 @@ namespace SixLabors.ImageSharp /// /// Create a new instance of the class from the given stream. /// - /// The Configuration. + /// The Configuration. /// The stream containing image information. /// The decoder. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. /// A new .> - public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) + public static Image Load(Configuration configuration, Stream stream, IImageDecoder decoder) where TPixel : unmanaged, IPixel - => WithSeekableStream(config, stream, s => decoder.Decode(config, s)); + => WithSeekableStream(configuration, stream, s => decoder.Decode(configuration, s)); /// /// Create a new instance of the class from the given stream. /// - /// The configuration options. + /// The configuration options. /// The stream containing image information. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. /// A new .> - public static Image Load(Configuration config, Stream stream) + public static Image Load(Configuration configuration, Stream stream) where TPixel : unmanaged, IPixel - => Load(config, stream, out IImageFormat _); + => Load(configuration, stream, out IImageFormat _); /// /// Create a new instance of the class from the given stream. /// - /// The configuration options. + /// The configuration options. /// The stream containing image information. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// The pixel format. - /// A new .> - public static Image Load(Configuration config, Stream stream, out IImageFormat format) + /// A new . + public static Image Load(Configuration configuration, Stream stream, out IImageFormat format) where TPixel : unmanaged, IPixel { - config = config ?? Configuration.Default; - (Image img, IImageFormat format) data = WithSeekableStream(config, stream, s => Decode(s, config)); + Guard.NotNull(configuration, nameof(configuration)); + (Image img, IImageFormat format) data = WithSeekableStream(configuration, stream, s => Decode(s, configuration)); format = data.format; @@ -218,7 +218,7 @@ namespace SixLabors.ImageSharp var sb = new StringBuilder(); sb.AppendLine("Image cannot be loaded. Available decoders:"); - foreach (KeyValuePair val in config.ImageFormatsManager.ImageDecoders) + foreach (KeyValuePair val in configuration.ImageFormatsManager.ImageDecoders) { sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } @@ -230,16 +230,16 @@ namespace SixLabors.ImageSharp /// Decode a new instance of the class from the given stream. /// The pixel format is selected by the decoder. /// - /// The configuration options. + /// The configuration options. /// The stream containing image information. /// The format type of the decoded image. /// Thrown if the stream is not readable. /// Image cannot be loaded. /// A new . - public static Image Load(Configuration config, Stream stream, out IImageFormat format) + public static Image Load(Configuration configuration, Stream stream, out IImageFormat format) { - config = config ?? Configuration.Default; - (Image img, IImageFormat format) data = WithSeekableStream(config, stream, s => Decode(s, config)); + Guard.NotNull(configuration, nameof(configuration)); + (Image img, IImageFormat format) data = WithSeekableStream(configuration, stream, s => Decode(s, configuration)); format = data.format; @@ -251,7 +251,7 @@ namespace SixLabors.ImageSharp var sb = new StringBuilder(); sb.AppendLine("Image cannot be loaded. Available decoders:"); - foreach (KeyValuePair val in config.ImageFormatsManager.ImageDecoders) + foreach (KeyValuePair val in configuration.ImageFormatsManager.ImageDecoders) { sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } @@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp throw new UnknownImageFormatException(sb.ToString()); } - private static T WithSeekableStream(Configuration config, Stream stream, Func action) + private static T WithSeekableStream(Configuration configuration, Stream stream, Func action) { if (!stream.CanRead) { @@ -268,7 +268,7 @@ namespace SixLabors.ImageSharp if (stream.CanSeek) { - if (config.ReadOrigin == ReadOrigin.Begin) + if (configuration.ReadOrigin == ReadOrigin.Begin) { stream.Position = 0; } From e4b239910a31d6069c16bfcb681edeb3b4f84810 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 24 Mar 2020 14:50:03 +0000 Subject: [PATCH 062/213] Replace Vector4.Clamp --- src/ImageSharp/ColorSpaces/Cmyk.cs | 2 +- .../Common/Helpers/DenseMatrixUtils.cs | 12 ++-- .../SimdUtils.FallbackIntrinsics128.cs | 4 +- src/ImageSharp/Common/Helpers/SimdUtils.cs | 2 +- .../{Vector4Utils.cs => Vector4Utilities.cs} | 18 +++++- .../Jpeg/Components/Block8x8F.Generated.cs | 32 +++++----- .../Jpeg/Components/Block8x8F.Generated.tt | 2 +- .../Formats/Jpeg/Components/Block8x8F.cs | 2 +- .../PixelImplementations/Argb32.cs | 2 +- .../PixelImplementations/Bgra32.cs | 2 +- .../PixelImplementations/Bgra4444.cs | 2 +- .../PixelImplementations/Bgra5551.cs | 2 +- .../PixelImplementations/Byte4.cs | 2 +- .../PixelFormats/PixelImplementations/L16.cs | 2 +- .../PixelFormats/PixelImplementations/L8.cs | 2 +- .../PixelFormats/PixelImplementations/La16.cs | 2 +- .../PixelFormats/PixelImplementations/La32.cs | 2 +- .../PixelImplementations/NormalizedByte4.cs | 2 +- .../PixelImplementations/NormalizedShort4.cs | 2 +- .../PixelImplementations/Rgb24.cs | 2 +- .../PixelImplementations/Rgb48.cs | 2 +- .../PixelImplementations/Rgba1010102.cs | 2 +- .../PixelImplementations/Rgba32.cs | 4 +- .../PixelImplementations/Rgba64.cs | 4 +- .../PixelImplementations/RgbaVector.cs | 2 +- .../PixelImplementations/Short4.cs | 2 +- .../PixelFormats/Utils/Vector4Converters.cs | 4 +- .../Convolution/BokehBlurProcessor{TPixel}.cs | 2 +- .../Filters/FilterProcessor{TPixel}.cs | 2 +- .../Linear/LinearTransformUtilities.cs | 6 +- .../General/BasicMath/ClampVector4.cs | 60 +++++++++++++++++++ .../Helpers/Vector4UtilsTests.cs | 8 +-- .../PixelOperations/PixelOperationsTests.cs | 24 ++++---- 33 files changed, 145 insertions(+), 75 deletions(-) rename src/ImageSharp/Common/Helpers/{Vector4Utils.cs => Vector4Utilities.cs} (85%) create mode 100644 tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index c2331c3798..5229cf14fb 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public Cmyk(Vector4 vector) { - vector = Vector4.Clamp(vector, Min, Max); + vector = Vector4Utilities.FastClamp(vector, Min, Max); this.C = vector.X; this.M = vector.Y; this.Y = vector.Z; diff --git a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs index bd25a7b440..462eeb3021 100644 --- a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs +++ b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); vector.W = target.W; - Vector4Utils.UnPremultiply(ref vector); + Vector4Utilities.UnPremultiply(ref vector); target = vector; } @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp out Vector4 vector); ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); - Vector4Utils.UnPremultiply(ref vector); + Vector4Utilities.UnPremultiply(ref vector); target = vector; } @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp { int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn); var currentColor = sourceRowSpan[offsetX].ToVector4(); - Vector4Utils.Premultiply(ref currentColor); + Vector4Utilities.Premultiply(ref currentColor); vectorX += matrixX[y, x] * currentColor; vectorY += matrixY[y, x] * currentColor; @@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); vector.W = target.W; - Vector4Utils.UnPremultiply(ref vector); + Vector4Utilities.UnPremultiply(ref vector); target = vector; } @@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp ref vector); ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); - Vector4Utils.UnPremultiply(ref vector); + Vector4Utilities.UnPremultiply(ref vector); target = vector; } @@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp { int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn); var currentColor = sourceRowSpan[offsetX].ToVector4(); - Vector4Utils.Premultiply(ref currentColor); + Vector4Utilities.Premultiply(ref currentColor); vector += matrix[y, x] * currentColor; } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index aaacfdd85c..6a93f9efc5 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -125,8 +125,6 @@ namespace SixLabors.ImageSharp Vector4 s = Unsafe.Add(ref sBase, i); s *= maxBytes; s += half; - - // I'm not sure if Vector4.Clamp() is properly implemented with intrinsics. s = Vector4.Max(Vector4.Zero, s); s = Vector4.Min(maxBytes, s); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index b58ec900f3..0dc45d887b 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Vector4 PseudoRound(this Vector4 v) { - var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1)); + var sign = Vector4Utilities.FastClamp(v, new Vector4(-1), new Vector4(1)); return v + (sign * 0.5f); } diff --git a/src/ImageSharp/Common/Helpers/Vector4Utils.cs b/src/ImageSharp/Common/Helpers/Vector4Utilities.cs similarity index 85% rename from src/ImageSharp/Common/Helpers/Vector4Utils.cs rename to src/ImageSharp/Common/Helpers/Vector4Utilities.cs index 594a5ff103..02bb4d9162 100644 --- a/src/ImageSharp/Common/Helpers/Vector4Utils.cs +++ b/src/ImageSharp/Common/Helpers/Vector4Utilities.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -11,8 +11,20 @@ namespace SixLabors.ImageSharp /// /// Utility methods for the struct. /// - internal static class Vector4Utils + internal static class Vector4Utilities { + /// + /// Restricts a vector between a minimum and a maximum value. + /// 5x Faster then . + /// + /// The vector to restrict. + /// The minimum value. + /// The maximum value. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static Vector4 FastClamp(Vector4 x, Vector4 min, Vector4 max) + => Vector4.Min(Vector4.Max(min, x), max); + /// /// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. /// @@ -107,4 +119,4 @@ namespace SixLabors.ImageSharp } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index 033eedb924..8e14ed2c36 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -99,22 +99,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components var CMax4 = new Vector4(maximum); var COff4 = new Vector4(MathF.Ceiling(maximum / 2)); - this.V0L = Vector4.Clamp(this.V0L + COff4, CMin4, CMax4); - this.V0R = Vector4.Clamp(this.V0R + COff4, CMin4, CMax4); - this.V1L = Vector4.Clamp(this.V1L + COff4, CMin4, CMax4); - this.V1R = Vector4.Clamp(this.V1R + COff4, CMin4, CMax4); - this.V2L = Vector4.Clamp(this.V2L + COff4, CMin4, CMax4); - this.V2R = Vector4.Clamp(this.V2R + COff4, CMin4, CMax4); - this.V3L = Vector4.Clamp(this.V3L + COff4, CMin4, CMax4); - this.V3R = Vector4.Clamp(this.V3R + COff4, CMin4, CMax4); - this.V4L = Vector4.Clamp(this.V4L + COff4, CMin4, CMax4); - this.V4R = Vector4.Clamp(this.V4R + COff4, CMin4, CMax4); - this.V5L = Vector4.Clamp(this.V5L + COff4, CMin4, CMax4); - this.V5R = Vector4.Clamp(this.V5R + COff4, CMin4, CMax4); - this.V6L = Vector4.Clamp(this.V6L + COff4, CMin4, CMax4); - this.V6R = Vector4.Clamp(this.V6R + COff4, CMin4, CMax4); - this.V7L = Vector4.Clamp(this.V7L + COff4, CMin4, CMax4); - this.V7R = Vector4.Clamp(this.V7R + COff4, CMin4, CMax4); + this.V0L = Vector4Utilities.FastClamp(this.V0L + COff4, CMin4, CMax4); + this.V0R = Vector4Utilities.FastClamp(this.V0R + COff4, CMin4, CMax4); + this.V1L = Vector4Utilities.FastClamp(this.V1L + COff4, CMin4, CMax4); + this.V1R = Vector4Utilities.FastClamp(this.V1R + COff4, CMin4, CMax4); + this.V2L = Vector4Utilities.FastClamp(this.V2L + COff4, CMin4, CMax4); + this.V2R = Vector4Utilities.FastClamp(this.V2R + COff4, CMin4, CMax4); + this.V3L = Vector4Utilities.FastClamp(this.V3L + COff4, CMin4, CMax4); + this.V3R = Vector4Utilities.FastClamp(this.V3R + COff4, CMin4, CMax4); + this.V4L = Vector4Utilities.FastClamp(this.V4L + COff4, CMin4, CMax4); + this.V4R = Vector4Utilities.FastClamp(this.V4R + COff4, CMin4, CMax4); + this.V5L = Vector4Utilities.FastClamp(this.V5L + COff4, CMin4, CMax4); + this.V5R = Vector4Utilities.FastClamp(this.V5R + COff4, CMin4, CMax4); + this.V6L = Vector4Utilities.FastClamp(this.V6L + COff4, CMin4, CMax4); + this.V6R = Vector4Utilities.FastClamp(this.V6R + COff4, CMin4, CMax4); + this.V7L = Vector4Utilities.FastClamp(this.V7L + COff4, CMin4, CMax4); + this.V7R = Vector4Utilities.FastClamp(this.V7R + COff4, CMin4, CMax4); } /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index 5370f27048..a1a6b01726 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components for (int j = 0; j < 2; j++) { char side = j == 0 ? 'L' : 'R'; - Write($"this.V{i}{side} = Vector4.Clamp(this.V{i}{side} + COff4, CMin4, CMax4);\r\n"); + Write($"this.V{i}{side} = Vector4Utilities.FastClamp(this.V{i}{side} + COff4, CMin4, CMax4);\r\n"); } } PopIndent(); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 868faceeaa..70a34ddcfa 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -589,7 +589,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) { // sign(dividend) = max(min(dividend, 1), -1) - var sign = Vector4.Clamp(dividend, NegativeOne, Vector4.One); + var sign = Vector4Utilities.FastClamp(dividend, NegativeOne, Vector4.One); // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend) return (dividend / divisor) + (sign * Offset); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index d5f4c54fb7..52f6bcaa19 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -373,7 +373,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.R = (byte)vector.X; this.G = (byte)vector.Y; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 0f2991a356..40c187eb27 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -296,7 +296,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.R = (byte)vector.X; this.G = (byte)vector.Y; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index f068312842..bbbf9145c7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static ushort Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One); return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) | (((int)Math.Round(vector.X * 15F) & 0x0F) << 8) | (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 92f2a3f75c..d10d10b477 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static ushort Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One); return (ushort)( (((int)Math.Round(vector.X * 31F) & 0x1F) << 10) | (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index 728966b00f..49b4f4138e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats const float Max = 255F; // Clamp the value between min and max values - vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max)); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, new Vector4(Max)); uint byte4 = (uint)Math.Round(vector.X) & 0xFF; uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 7235abd21c..815ae6a4e3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] internal void ConvertFromRgbaScaledVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.PackedValue = ImageMaths.Get16BitBT709Luminance( vector.X, vector.Y, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index c622f17508..37a028db25 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 66cb757c30..104c2be45a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.L = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); this.A = (byte)vector.W; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index 4885dae615..98a6cdae49 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] internal void ConvertFromRgbaScaledVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.L = ImageMaths.Get16BitBT709Luminance( vector.X, vector.Y, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 3a4b92ff32..a7b350d557 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half; + vector = Vector4Utilities.FastClamp(vector, MinusOne, Vector4.One) * Half; uint byte4 = ((uint)MathF.Round(vector.X) & 0xFF) << 0; uint byte3 = ((uint)MathF.Round(vector.Y) & 0xFF) << 8; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 052e44f714..59433f17e2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats private static ulong Pack(ref Vector4 vector) { vector *= Max; - vector = Vector4.Clamp(vector, Min, Max); + vector = Vector4Utilities.FastClamp(vector, Min, Max); // Round rather than truncate. ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 5eb7b74b26..6e4839fed7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -254,7 +254,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.R = (byte)vector.X; this.G = (byte)vector.Y; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index e494ff68e4..dff8fe83fe 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); this.G = (ushort)MathF.Round(vector.Y); this.B = (ushort)MathF.Round(vector.Z); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 2b5670778c..7ca47f8387 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static uint Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Multiplier; return (uint)( (((int)Math.Round(vector.X) & 0x03FF) << 0) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 8f67f2166c..43ec095a12 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); return new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, (byte)vector.W); } @@ -491,7 +491,7 @@ namespace SixLabors.ImageSharp.PixelFormats { vector *= MaxBytes; vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes); this.R = (byte)vector.X; this.G = (byte)vector.Y; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 88ef1dc989..8e5f8f0938 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public Rgba64(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); this.G = (ushort)MathF.Round(vector.Y); this.B = (ushort)MathF.Round(vector.Z); @@ -209,7 +209,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max; this.R = (ushort)MathF.Round(vector.X); this.G = (ushort)MathF.Round(vector.Y); this.B = (ushort)MathF.Round(vector.Z); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 8a6bc94a76..8a6f882c35 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] public void FromVector4(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One); this.R = vector.X; this.G = vector.Y; this.B = vector.Z; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index e709cd04fd..135aa8d582 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.PixelFormats [MethodImpl(InliningOptions.ShortMethod)] private static ulong Pack(ref Vector4 vector) { - vector = Vector4.Clamp(vector, Min, Max); + vector = Vector4Utilities.FastClamp(vector, Min, Max); // Clamp the value between min and max values ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00; diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs index 447869a7d5..ba676b3b88 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils if (modifiers.IsDefined(PixelConversionModifiers.Premultiply)) { - Vector4Utils.Premultiply(vectors); + Vector4Utilities.Premultiply(vectors); } } @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils { if (modifiers.IsDefined(PixelConversionModifiers.Premultiply)) { - Vector4Utils.UnPremultiply(vectors); + Vector4Utilities.UnPremultiply(vectors); } if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand)) diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index 493218cde5..cf97751bef 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -304,7 +304,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int x = 0; x < this.bounds.Width; x++) { ref Vector4 v = ref Unsafe.Add(ref sourceRef, x); - var clamp = Vector4.Clamp(v, low, high); + var clamp = Vector4Utilities.FastClamp(v, low, high); v.X = MathF.Pow(clamp.X, this.inverseGamma); v.Y = MathF.Pow(clamp.Y, this.inverseGamma); v.Z = MathF.Pow(clamp.Z, this.inverseGamma); diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index 7da4eb1b10..dee9d2ff62 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span); - Vector4Utils.Transform(span, ref Unsafe.AsRef(this.matrix)); + Vector4Utilities.Transform(span, ref Unsafe.AsRef(this.matrix)); PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs index 04aaa11021..0a00cf8e9b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms MathF.Floor(maxXY.X), MathF.Floor(maxXY.Y)); - sourceExtents = Vector4.Clamp(sourceExtents, Vector4.Zero, maxSourceExtents); + sourceExtents = Vector4Utilities.FastClamp(sourceExtents, Vector4.Zero, maxSourceExtents); int left = (int)sourceExtents.X; int top = (int)sourceExtents.Y; @@ -78,13 +78,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Values are first premultiplied to prevent darkening of edge pixels. var current = sourcePixels[x, y].ToVector4(); - Vector4Utils.Premultiply(ref current); + Vector4Utilities.Premultiply(ref current); sum += current * xWeight * yWeight; } } // Reverse the premultiplication - Vector4Utils.UnPremultiply(ref sum); + Vector4Utilities.UnPremultiply(ref sum); targetRow[column] = sum; } diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs new file mode 100644 index 0000000000..8cbb31d218 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Text; +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + public class ClampVector4 + { + private readonly float min = -1.5f; + private readonly float max = 2.5f; + private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 }; + + [Benchmark(Baseline = true)] + public Vector4 UsingVectorClamp() + { + Vector4 acc = Vector4.Zero; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingVectorClamp(Values[i], this.min, this.max); + } + + return acc; + } + + [Benchmark] + public Vector4 UsingVectorMinMax() + { + Vector4 acc = Vector4.Zero; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingVectorMinMax(Values[i], this.min, this.max); + } + + return acc; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector4 ClampUsingVectorClamp(float x, float min, float max) + { + return Vector4.Clamp(new Vector4(x), new Vector4(min), new Vector4(max)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector4 ClampUsingVectorMinMax(float x, float min, float max) + { + return Vector4.Min(new Vector4(max), Vector4.Max(new Vector4(min), new Vector4(x))); + } + + // RESULTS + // | Method | Mean | Error | StdDev | Ratio | + // |------------------ |---------:|---------:|---------:|------:| + // | UsingVectorClamp | 75.21 ns | 1.572 ns | 4.057 ns | 1.00 | + // | UsingVectorMinMax | 15.35 ns | 0.356 ns | 0.789 ns | 0.20 | + } +} diff --git a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs index af789a9b6a..bc1ffda48f 100644 --- a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs @@ -23,11 +23,11 @@ namespace SixLabors.ImageSharp.Tests.Helpers Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); Vector4[] expected = source.Select(v => { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); return v; }).ToArray(); - Vector4Utils.Premultiply(source); + Vector4Utilities.Premultiply(source); Assert.Equal(expected, source, this.approximateFloatComparer); } @@ -42,11 +42,11 @@ namespace SixLabors.ImageSharp.Tests.Helpers Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); Vector4[] expected = source.Select(v => { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); return v; }).ToArray(); - Vector4Utils.UnPremultiply(source); + Vector4Utilities.UnPremultiply(source); Assert.Equal(expected, source, this.approximateFloatComparer); } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index b2b39b590d..9d48675f16 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } } @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } } @@ -199,7 +199,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } } @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } } @@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations if (this.HasAlpha) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } } @@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { if (this.HasAlpha) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } SRgbCompanding.Compress(ref v); @@ -349,12 +349,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { void SourceAction(ref Vector4 v) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } void ExpectedAction(ref Vector4 v) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } TPixel[] source = CreatePixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); @@ -372,12 +372,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { void SourceAction(ref Vector4 v) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); } void ExpectedAction(ref Vector4 v) { - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); @@ -399,14 +399,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { void SourceAction(ref Vector4 v) { - Vector4Utils.UnPremultiply(ref v); + Vector4Utilities.UnPremultiply(ref v); SRgbCompanding.Compress(ref v); } void ExpectedAction(ref Vector4 v) { SRgbCompanding.Expand(ref v); - Vector4Utils.Premultiply(ref v); + Vector4Utilities.Premultiply(ref v); } TPixel[] source = CreateScaledPixelTestData(count, (ref Vector4 v) => SourceAction(ref v)); From 55f60a2e65356877dcfb8295a3ce04cf55a0f568 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 24 Mar 2020 21:13:21 +0100 Subject: [PATCH 063/213] Add missing copyright note in ClampVector4 --- .../General/BasicMath/ClampVector4.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs index 8cbb31d218..145b98b0f4 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs @@ -1,8 +1,9 @@ -using System; -using System.Collections.Generic; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + using System.Numerics; using System.Runtime.CompilerServices; -using System.Text; + using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath From f36930dcc088f88f92f4e7bf42424ffb5f875b6e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 25 Mar 2020 09:25:37 +0000 Subject: [PATCH 064/213] Update based on Tanner's investigationl. --- .../Common/Helpers/SimdUtils.FallbackIntrinsics128.cs | 3 +-- src/ImageSharp/Common/Helpers/Vector4Utilities.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index 6a93f9efc5..f16c91b40d 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -125,8 +125,7 @@ namespace SixLabors.ImageSharp Vector4 s = Unsafe.Add(ref sBase, i); s *= maxBytes; s += half; - s = Vector4.Max(Vector4.Zero, s); - s = Vector4.Min(maxBytes, s); + s = Vector4Utilities.FastClamp(s, Vector4.Zero, maxBytes); ref ByteVector4 d = ref Unsafe.Add(ref dBase, i); d.X = (byte)s.X; diff --git a/src/ImageSharp/Common/Helpers/Vector4Utilities.cs b/src/ImageSharp/Common/Helpers/Vector4Utilities.cs index 02bb4d9162..9fb4eb7909 100644 --- a/src/ImageSharp/Common/Helpers/Vector4Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector4Utilities.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp /// The . [MethodImpl(InliningOptions.ShortMethod)] public static Vector4 FastClamp(Vector4 x, Vector4 min, Vector4 max) - => Vector4.Min(Vector4.Max(min, x), max); + => Vector4.Min(Vector4.Max(x, min), max); /// /// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. From 6346be9d209c4d6545e32262f23f352e5ca63e49 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 25 Mar 2020 16:21:26 +0000 Subject: [PATCH 065/213] Update ImageExtensions.cs --- src/ImageSharp/ImageExtensions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 24d2ad49bc..3cb4f433ec 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. using System; +#if !SUPPORTS_BASE64SPAN using System.Buffers; +#endif using System.Collections.Generic; using System.IO; using System.Text; From c3cb0e4b389c64c0dc2ad65bd728a5126dfb178b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 25 Mar 2020 17:57:42 +0000 Subject: [PATCH 066/213] Simplify approach --- Directory.Build.props | 28 ++++++++++++++-------------- src/ImageSharp/ImageExtensions.cs | 27 +++++---------------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 2f9863561c..de3583a0c8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -31,27 +31,27 @@ - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE;SUPPORTS_BASE64SPAN + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE;SUPPORTS_BASE64SPAN + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_CODECOVERAGE;SUPPORTS_BASE64SPAN + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_CODECOVERAGE $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 3cb4f433ec..d7ac0b174d 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -115,29 +115,12 @@ namespace SixLabors.ImageSharp public static string ToBase64String(this Image source, IImageFormat format) where TPixel : unmanaged, IPixel { - using (var stream = new MemoryStream()) - { - source.Save(stream, format); - - // Always available. - stream.TryGetBuffer(out ArraySegment buffer); + using var stream = new MemoryStream(); + source.Save(stream, format); -#if !SUPPORTS_BASE64SPAN - - byte[] sharedBuffer = ArrayPool.Shared.Rent(buffer.Count); - try - { - buffer.AsSpan().CopyTo(sharedBuffer); - return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(sharedBuffer)}"; - } - finally - { - ArrayPool.Shared.Return(sharedBuffer); - } -#else - return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(buffer)}"; -#endif - } + // Always available. + stream.TryGetBuffer(out ArraySegment buffer); + return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(buffer.Array, 0, (int)stream.Length)}"; } } } From e957cf0d213f27bf88c21d701cc69f567b46a430 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 25 Mar 2020 17:58:48 +0000 Subject: [PATCH 067/213] Update Directory.Build.props --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index de3583a0c8..12a4a5c2a3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -35,7 +35,7 @@ | SUPPORTS | MATHF | HASHCODE | EXTENDED_INTRINSICS | SPAN_STREAM | ENCODING_STRING | RUNTIME_INTRINSICS | CODECOVERAGE | +===================+=======+==========+=====================+=============+=================+====================+==============+ | netcoreapp3.1 | Y | Y | Y | Y | Y | Y | Y | - | netcoreapp2.1 | Y | Y | Y | Y | Y | N | Y | + | netcoreapp2.1 | Y | Y | Y | Y | Y | N | Y | | netcoreapp2.0 | Y | N | N | N | N | N | Y | | netstandard2.1 | Y | Y | N | Y | Y | N | Y | | netstandard2.0 | N | N | N | N | N | N | Y | From 3dd4951bb3c508a5d30168d05d7110b78aea551d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 25 Mar 2020 17:59:49 +0000 Subject: [PATCH 068/213] Update ImageExtensions.cs --- src/ImageSharp/ImageExtensions.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index d7ac0b174d..0bdbcc4ab3 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -2,9 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -#if !SUPPORTS_BASE64SPAN -using System.Buffers; -#endif using System.Collections.Generic; using System.IO; using System.Text; From 79350798146eb6a8f27c84017603132c423802bf Mon Sep 17 00:00:00 2001 From: samsosa <32570890+samsosa@users.noreply.github.com> Date: Thu, 26 Mar 2020 00:49:56 +0100 Subject: [PATCH 069/213] Simple copy & paste error fixed --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 92430c915d..fb1f88a2da 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -359,7 +359,7 @@ namespace SixLabors.ImageSharp } } - return height; + return width; } topLeft.Y = GetMinY(bitmap); From e80a6e33e4d9c6d4eedf2da7729516ab6e8add54 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 26 Mar 2020 09:58:49 +0100 Subject: [PATCH 070/213] Add image extension method for save as tga --- src/ImageSharp/Formats/Tga/ImageExtensions.cs | 36 +++++++++++++++++++ .../Formats/GeneralFormatTests.cs | 19 ++++++---- .../Formats/ImageFormatManagerTests.cs | 5 ++- 3 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 src/ImageSharp/Formats/Tga/ImageExtensions.cs diff --git a/src/ImageSharp/Formats/Tga/ImageExtensions.cs b/src/ImageSharp/Formats/Tga/ImageExtensions.cs new file mode 100644 index 0000000000..286f04a226 --- /dev/null +++ b/src/ImageSharp/Formats/Tga/ImageExtensions.cs @@ -0,0 +1,36 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; + +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats.Tga; + +namespace SixLabors.ImageSharp +{ + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Saves the image to the given stream with the tga format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// Thrown if the stream is null. + public static void SaveAsTga(this Image source, Stream stream) => SaveAsTga(source, stream, null); + + /// + /// Saves the image to the given stream with the tga format. + /// + /// The image this method extends. + /// The stream to save the image to. + /// The options for the encoder. + /// Thrown if the stream is null. + public static void SaveAsTga(this Image source, Stream stream, TgaEncoder encoder) => + source.Save( + stream, + encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TgaFormat.Instance)); + } +} diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index e6b6e43c17..ca236e9146 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -15,7 +15,7 @@ using SixLabors.ImageSharp.Processing.Processors.Quantization; using Xunit; -namespace SixLabors.ImageSharp.Tests +namespace SixLabors.ImageSharp.Tests.Formats { public class GeneralFormatTests : FileTestBase { @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests { using (Image image = file.CreateRgba32Image()) { - string filename = path + "/" + file.FileNameWithoutExtension + ".txt"; + string filename = Path.Combine(path, $"{file.FileNameWithoutExtension}.txt"); File.WriteAllText(filename, image.ToBase64String(PngFormat.Instance)); } } @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests { using (Image image = file.CreateRgba32Image()) { - image.Save($"{path}/{file.FileName}"); + image.Save(Path.Combine(path, file.FileName)); } } } @@ -103,25 +103,30 @@ namespace SixLabors.ImageSharp.Tests { using (Image image = file.CreateRgba32Image()) { - using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.bmp")) + using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.bmp"))) { image.SaveAsBmp(output); } - using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.jpg")) + using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.jpg"))) { image.SaveAsJpeg(output); } - using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png")) + using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.png"))) { image.SaveAsPng(output); } - using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.gif")) + using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.gif"))) { image.SaveAsGif(output); } + + using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.tga"))) + { + image.SaveAsTga(output); + } } } } diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index d011a63301..9dba7179d9 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -10,10 +10,11 @@ using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.PixelFormats; using Xunit; -namespace SixLabors.ImageSharp.Tests +namespace SixLabors.ImageSharp.Tests.Formats { public class ImageFormatManagerTests { @@ -34,11 +35,13 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); + Assert.Equal(1, this.DefaultFormatsManager.ImageEncoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); + Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); } [Fact] From 43ed06ed71fbf73891839504778d5445e96e575d Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 26 Mar 2020 12:38:32 +0100 Subject: [PATCH 071/213] Add unit test for #1154: entropy crop on white image should not crop --- .../Processors/Transforms/EntropyCropTest.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs index a04aef6bca..6ba795e560 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using Xunit; @@ -27,5 +26,24 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { provider.RunValidatingProcessorTest(x => x.EntropyCrop(value), value, appendPixelTypeToFileName: false); } + + [Theory] + [WithBlankImages(40, 30, PixelTypes.Rgba32)] + [WithBlankImages(30, 40, PixelTypes.Rgba32)] + public void Entropy_WillNotCropWhiteImage(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + // arrange + using Image image = provider.GetImage(); + var expectedHeight = image.Height; + var expectedWidth = image.Width; + + // act + image.Mutate(img => img.EntropyCrop()); + + // assert + Assert.Equal(image.Width, expectedWidth); + Assert.Equal(image.Height, expectedHeight); + } } } From 1fd1a621369cd896f5a9717697bc460f5fb0b3a7 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 26 Mar 2020 19:52:57 +0100 Subject: [PATCH 072/213] Respect alpha channel bits from image descriptor during tga decoding --- src/ImageSharp/Formats/Tga/TgaDecoder.cs | 1 - src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 138 +++++++++++++----- src/ImageSharp/Formats/Tga/TgaMetadata.cs | 5 + .../Formats/Tga/TgaDecoderTests.cs | 15 ++ tests/ImageSharp.Tests/TestImages.cs | 4 + tests/Images/Input/Tga/16bit_noalphabits.tga | Bin 0 -> 96818 bytes .../Input/Tga/16bit_rle_noalphabits.tga | Bin 0 -> 138354 bytes tests/Images/Input/Tga/32bit_noalphabits.tga | Bin 0 -> 61522 bytes .../Input/Tga/32bit_rle_no_alphabits.tga | Bin 0 -> 230578 bytes 9 files changed, 126 insertions(+), 37 deletions(-) create mode 100644 tests/Images/Input/Tga/16bit_noalphabits.tga create mode 100644 tests/Images/Input/Tga/16bit_rle_noalphabits.tga create mode 100644 tests/Images/Input/Tga/32bit_noalphabits.tga create mode 100644 tests/Images/Input/Tga/32bit_rle_no_alphabits.tga diff --git a/src/ImageSharp/Formats/Tga/TgaDecoder.cs b/src/ImageSharp/Formats/Tga/TgaDecoder.cs index 2249c86bf9..c3b8526ceb 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoder.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoder.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index ead0040038..bba04f98a4 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -12,6 +12,9 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Tga { + /// + /// Performs the tga decoding operation. + /// internal sealed class TgaDecoderCore { /// @@ -49,6 +52,11 @@ namespace SixLabors.ImageSharp.Formats.Tga /// private readonly ITgaDecoderOptions options; + /// + /// Indicates whether there is a alpha channel present. + /// + private bool hasAlpha; + /// /// Initializes a new instance of the class. /// @@ -89,7 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Tga TgaThrowHelper.ThrowNotSupportedException($"Unknown tga colormap type {this.fileHeader.ColorMapType} found"); } - if (this.fileHeader.Width == 0 || this.fileHeader.Height == 0) + if (this.fileHeader.Width is 0 || this.fileHeader.Height is 0) { throw new UnknownImageFormatException("Width or height cannot be 0"); } @@ -199,7 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Tga break; default: - TgaThrowHelper.ThrowNotSupportedException("Does not support this kind of tga files."); + TgaThrowHelper.ThrowNotSupportedException("ImageSharp does not support this kind of tga files."); break; } @@ -241,9 +249,13 @@ namespace SixLabors.ImageSharp.Formats.Tga { int colorIndex = rowSpan[x]; - // Set alpha value to 1, to treat it as opaque for Bgra5551. Bgra5551 bgra = Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes]); - bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); + if (!this.hasAlpha) + { + // Set alpha value to 1, to treat it as opaque for Bgra5551. + bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); + } + color.FromBgra5551(bgra); pixelRow[x] = color; } @@ -291,6 +303,7 @@ namespace SixLabors.ImageSharp.Formats.Tga using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * bytesPerPixel, AllocationOptions.Clean)) { TPixel color = default; + var alphaBits = this.tgaMetadata.AlphaChannelBits; Span bufferSpan = buffer.GetSpan(); this.UncompressRle(width, height, bufferSpan, bytesPerPixel: 1); @@ -308,16 +321,30 @@ namespace SixLabors.ImageSharp.Formats.Tga color.FromL8(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 2: - // Set alpha value to 1, to treat it as opaque for Bgra5551. + Bgra5551 bgra = Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]); - bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); + if (!this.hasAlpha) + { + // Set alpha value to 1, to treat it as opaque for Bgra5551. + bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); + } + color.FromBgra5551(bgra); break; case 3: color.FromBgr24(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 4: - color.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); + if (this.hasAlpha) + { + color.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); + } + else + { + var alpha = alphaBits is 0 ? byte.MaxValue : bufferSpan[idx + 3]; + color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], (byte)alpha)); + } + break; } @@ -345,11 +372,7 @@ namespace SixLabors.ImageSharp.Formats.Tga this.currentStream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromL8Bytes( - this.configuration, - row.GetSpan(), - pixelSpan, - width); + PixelOperations.Instance.FromL8Bytes(this.configuration, row.GetSpan(), pixelSpan, width); } } } @@ -372,19 +395,18 @@ namespace SixLabors.ImageSharp.Formats.Tga this.currentStream.Read(row); Span rowSpan = row.GetSpan(); - // We need to set each alpha component value to fully opaque. - for (int x = 1; x < rowSpan.Length; x += 2) + if (!this.hasAlpha) { - rowSpan[x] = (byte)(rowSpan[x] | (1 << 7)); + // We need to set the alpha component value to fully opaque. + for (int x = 1; x < rowSpan.Length; x += 2) + { + rowSpan[x] = (byte)(rowSpan[x] | (1 << 7)); + } } int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgra5551Bytes( - this.configuration, - rowSpan, - pixelSpan, - width); + PixelOperations.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width); } } } @@ -407,11 +429,7 @@ namespace SixLabors.ImageSharp.Formats.Tga this.currentStream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgr24Bytes( - this.configuration, - row.GetSpan(), - pixelSpan, - width); + PixelOperations.Instance.FromBgr24Bytes(this.configuration, row.GetSpan(), pixelSpan, width); } } } @@ -427,18 +445,41 @@ namespace SixLabors.ImageSharp.Formats.Tga private void ReadBgra32(int width, int height, Buffer2D pixels, bool inverted) where TPixel : unmanaged, IPixel { + if (this.tgaMetadata.AlphaChannelBits is 8) + { + using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0)) + { + for (int y = 0; y < height; y++) + { + this.currentStream.Read(row); + int newY = Invert(y, height, inverted); + Span pixelSpan = pixels.GetRowSpan(newY); + + PixelOperations.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width); + } + } + + return; + } + + TPixel color = default; + var alphaBits = this.tgaMetadata.AlphaChannelBits; using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0)) { for (int y = 0; y < height; y++) { this.currentStream.Read(row); int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgra32Bytes( - this.configuration, - row.GetSpan(), - pixelSpan, - width); + Span pixelRow = pixels.GetRowSpan(newY); + Span rowSpan = row.GetSpan(); + + for (int x = 0; x < width; x++) + { + int idx = x * 4; + var alpha = alphaBits is 0 ? byte.MaxValue : rowSpan[idx + 3]; + color.FromBgra32(new Bgra32(rowSpan[idx + 2], rowSpan[idx + 1], rowSpan[idx], (byte)alpha)); + pixelRow[x] = color; + } } } } @@ -456,6 +497,7 @@ namespace SixLabors.ImageSharp.Formats.Tga where TPixel : unmanaged, IPixel { TPixel color = default; + var alphaBits = this.tgaMetadata.AlphaChannelBits; using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * bytesPerPixel, AllocationOptions.Clean)) { Span bufferSpan = buffer.GetSpan(); @@ -474,15 +516,28 @@ namespace SixLabors.ImageSharp.Formats.Tga color.FromL8(Unsafe.As(ref bufferSpan[idx])); break; case 2: - // Set alpha value to 1, to treat it as opaque for Bgra5551. - bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128); + if (!this.hasAlpha) + { + // Set alpha value to 1, to treat it as opaque for Bgra5551. + bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128); + } + color.FromBgra5551(Unsafe.As(ref bufferSpan[idx])); break; case 3: color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); break; case 4: - color.FromBgra32(Unsafe.As(ref bufferSpan[idx])); + if (this.hasAlpha) + { + color.FromBgra32(Unsafe.As(ref bufferSpan[idx])); + } + else + { + var alpha = alphaBits is 0 ? byte.MaxValue : bufferSpan[idx + 3]; + color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], (byte)alpha)); + } + break; } @@ -524,7 +579,7 @@ namespace SixLabors.ImageSharp.Formats.Tga // The high bit of a run length packet is set to 1. int highBit = runLengthByte >> 7; - if (highBit == 1) + if (highBit is 1) { int runLength = runLengthByte & 127; this.currentStream.Read(pixel, 0, bytesPerPixel); @@ -577,7 +632,18 @@ namespace SixLabors.ImageSharp.Formats.Tga this.tgaMetadata = this.metadata.GetTgaMetadata(); this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth; - // Bit at position 5 of the descriptor indicates, that the origin is top left instead of bottom right. + var alphaBits = this.fileHeader.ImageDescriptor & 0xf; + if (alphaBits != 0 && alphaBits != 1 && alphaBits != 8) + { + TgaThrowHelper.ThrowImageFormatException("Invalid alpha channel bits"); + } + + this.tgaMetadata.AlphaChannelBits = (byte)alphaBits; + this.hasAlpha = alphaBits > 0; + + // TODO: bits 4 and 5 describe the image origin. See spec page 9. bit 4 is currently ignored. + // Theoretically the origin could also be top right and bottom right. + // Bit at position 5 of the descriptor indicates, that the origin is top left instead of bottom left. if ((this.fileHeader.ImageDescriptor & (1 << 5)) != 0) { return true; diff --git a/src/ImageSharp/Formats/Tga/TgaMetadata.cs b/src/ImageSharp/Formats/Tga/TgaMetadata.cs index 4ce61d2e48..69dee768a9 100644 --- a/src/ImageSharp/Formats/Tga/TgaMetadata.cs +++ b/src/ImageSharp/Formats/Tga/TgaMetadata.cs @@ -29,6 +29,11 @@ namespace SixLabors.ImageSharp.Formats.Tga /// public TgaBitsPerPixel BitsPerPixel { get; set; } = TgaBitsPerPixel.Pixel24; + /// + /// Gets or sets the the number of alpha bits per pixel. + /// + public byte AlphaChannelBits { get; set; } = 0; + /// public IDeepCloneable DeepClone() => new TgaMetadata(this); } diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index bcd98d714c..ec2621e65c 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -198,6 +198,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(NoAlphaBits32Bit, PixelTypes.Rgba32)] + [WithFile(NoAlphaBits16Bit, PixelTypes.Rgba32)] + [WithFile(NoAlphaBits32BitRle, PixelTypes.Rgba32)] + [WithFile(NoAlphaBits16BitRle, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WhenAlphaBitsNotSet(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit16, PixelTypes.Rgba32)] [WithFile(Bit24, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 2e58ac970c..db4c9a4483 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -390,6 +390,10 @@ namespace SixLabors.ImageSharp.Tests public const string Bit32Rle = "Tga/targa_32bit_rle.tga"; public const string Bit16Pal = "Tga/targa_16bit_pal.tga"; public const string Bit24Pal = "Tga/targa_24bit_pal.tga"; + public const string NoAlphaBits16Bit = "Tga/16bit_noalphabits.tga"; + public const string NoAlphaBits16BitRle = "Tga/16bit_rle_noalphabits.tga"; + public const string NoAlphaBits32Bit = "Tga/32bit_noalphabits.tga"; + public const string NoAlphaBits32BitRle = "Tga/32bit_rle_no_alphabits.tga"; } } } diff --git a/tests/Images/Input/Tga/16bit_noalphabits.tga b/tests/Images/Input/Tga/16bit_noalphabits.tga new file mode 100644 index 0000000000000000000000000000000000000000..0e97e86e3d7da52e6a71a6532ae8ec3ecd2a5445 GIT binary patch literal 96818 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

St_ytT_q&(?NtZePzmA+Hu_jlOLOT>_2E*dh! zjN~8cdASFjL0nm~jl})| zImJ2hdLpPfsMndia=!Ty^EPj^Mq{_Bn=GXl@eZ7k??07~q)?i15Vu!VFOh%4Hb$+} zT#EC&+x6yofOFG6d1xcmec*Zvb!7gnf}2isgw%Soz0#c9Q`9CqDNE`0(#h#jk)nz^ z6rq^nq%-ydbdFfrI1E{wC~i5=RJN;-TjF0$Z(?q(_CouyeTi?el|+-Gr}_?+HO-xg zGPgpJNyu#qyQ=-}bEW)kp-cb9kX%5`_5)N~F2^NqBg4nNrnx>pPldgdl~hbAX5PtV zx-->L(XxpOUL%1XCvtAVkZcq?*774yfo+TN4@_pf4R=4w8Jee8Bm^UjNyFRZ2MO+DL+y;W0@EtSTck3UXTe5YU0 zuWNY@pG_TU4(ndTC&Z-6woBxcd&5!O%%);1ueV(1ZjkfMdCu-s7a9uNbrYYR+2#a2 z%=F&^H|jNIZu?&1ru@ygnVqyxsaeN>nJKQUH)+V@5@&|qP#kfJ$dPR*K6TZJooUXV z-Bx-ACvL7b>CK6W8XeiJe)0g-m$i(Xsm|+^*0G>jBpKDVh##?=iYMv+rgQ&yL*wzQ z)cwoUM6XW&nwWMq#Eo~mM9t%pphn9su4ZQvM`mw9b|tq;hI(CQCvtQB+oELNOnUPu z^03F2s(x9#;*q6Ob8-*41?x!Td$r$k>t;36W)*Mf4#kt%+T>NJUF$sCaUZ>f^AymV z@&MOc(9dP@Sotc)Y zi*c`hr!^D-^aRp_%~oJROMEc$093c^XcCsYmtW=OrTP29VS#K`EH7Su3*2Hn?Bi} zW2dJ~t^BHzo&QvN^S^B_|1Vu0dsy{EvocI?>N@eCYwDpWYGujgZZLP0ni?~}r;|+u zFZ7hy(;Eik#H-`!HB}us6kG7xA)SM6DcOq{*Cr> zoSIiDof|bvvbPuPci+pPyxx|9A2O34)_k~UC!aebBuZ{0v`-OmL;a>DxTz~h`ynDE zZsegvS@gxb9j&m6L<|;>=&?*rHd4#D@%ODOo=l%0QSx??qBIODCuM z!Ov4oQGe{8cP*#g2Cl(Yp5X2bc+k(PdP%4^{rYy#yN#R0lPTk7bp`3oEG7Oy|5}eL z`P`a^)7~0Nvv@SXhTo{Ywm3b?B^L-rbBdUWL`I~Z3 zZUW`>wk<3r{U!2ktdfc6U zDhE)dMAV2&vZu1A=z%#YYS>ZzRD_&US#Qjb&fnzMou2-rbF)WstP_d zO<|@x)vJ|vi>8s|`FzWHd>pqEZrZ-nxe+aWa-%<(FW;g4!tmY)*+~><8G-cX+{nAB zy{aChe?6br6+Yem&HD7>w?so~GAd4O1vjiEmPU1E{SNbP#*LY;%*1xDCR)TIHcN>6 z)1)}4af)5@E!0P;JOH&R2GKbVX)atLH<1%Jcb zh-%6rH0SgBc(jEeAoFNan*PiDGsSbrO*Hj8^f@v%@bV>U z;i6Ybuc7IRGIa%nLQ>ESsp;9iq`JBM!}RCF?~lDbvOV|z=pM(~BYbrPbVSJV0@+IA zr5s&x=P`cH4HMj19)+98g}!SmwUckV>Q-`tYsd|Ix^n)c$k~~K&_cRz*Zvz{C1TD^ zbxB2&m1}Q0n`#)I$=>hsoo=io#F$2JdjiCd#!Yu9vfE}JPTZKx#3@BOyQDWF6EO>7 zl7O4@D{~XIE16sIJrVIyRmOE@mYdh&=j5ClehzM-{}MNQ$4lJA&tev_(oB7<;?xRm zV&-2wmbmeXwXN{|==)PV&itTqm#fUlw2F!9B|2X~bP}EpSrv3^$xez_SesM~ znbVh@%rCRso9@fj4AR?*+NP7IOlN_QGqsuGpe75c9$xJLTRfusNqcniX29Z-S;Zt! zyKFwrGq{kOI?Xo}`p{UN^9p^f+iu?p3^XTh=Jx_S8Co}2O7Lhgq^mIG#&c=i5GSZX z44SfDM$YW!1^(>q;@e}Nj1BVj@yJx-f0d>tQ?$ySPq zqQ&0q7M&rHKl`qGqD_ zaCfO+_!A>&uKv9X=O7n1Hx6)3&J}{eG zVlHzhwwPuAHR^$u*7RS-v;JEHZp4$=NsEw7Zx!5>%~79}b(FU&aVzl($uaQ{RXI12 zbCu~Q7xD3%O0#=*uHCi$-`SjFx3$zj}AqF?G)7-u38KU`_UsmFzci6XxMy z7R-)(Ml5nqK5e)u(@8z8RQohm^pEl1qg|!YQhFR^afx(k{*Ap*V+Aig^K~n~q*)Io zZehF_5-UH8ny(ANvvaG<+!=j)`ZUxgLA?bl~Cu=GQHVZoFCiBJ*k)N;tFOWn5EvO z#rvs_AS|M(?sW3B*~R(fW2~dc{x!x8wV^lelodCNOH6M8H}h=ROp7Jy_TomPsPv@U zRQdard+7{q{+O;pYUDuVullZ!S3H}=41d*r z&O1Akx}Ck9x~({*=Qg@qhN0WYCNzd$vzZ8!JWF?z_%^(oY9opu2WN}x3w^TJfx?`Y zaSOEX|39Xy92$6jb(Di?E)ErR>+O)%@?uD zP3_~PUgf4%O~X?xSyEVH3)V&4pk~~N&}1czO<*bEQ}%7-uFi{Ru~U`V7e8m|{pI$| z6!VdZMb>K`vXlq6ZZbA`wt;|}Zf+~eR+@ivY7;~)bMd|0Dkmzk&_st)TCm(kuHY8< zxsaPC1&{}bS1JAvxm6d+{w-vu=d#+wO4Q2a#BELPi&6J&&W$sHnOvfm_<2<{D)wZ_N~Y#>El|nyy*K4*t3)dB zZ0e4b-sI(Zv`>2I(M|?jcn?`pTCY_dpk}|~imGW)`y?|=!qW_Tr^ifW`8FdZ zX3opcn%*l8Foi~^2^87O_WIHZEuHkyS0Dec{s}2P!c2JxR?^lA|K^^}^yWHSThJ0G zf40|_o9kzfSgx=iKb|f;9mcnfe1hH%a3l7_@Oj?3US?bMCLeUB$>mhxGUdSydx`3_ zu$lH#X-(|@|H960w~p!z!^b$Wf%YQW5Mrv7gC6vds5Ewt|*%uXR=W zi_J+Y4~hTSGO++)rwYni4TssKrh~&U)tBK1itRyVqiq zwWY~EVx~OgOwD>HX?teZ-}HqQYu(M4-X$)PZ!@(&%QiwyI`-}l+YfH+U*Aw2##@$F zG2g-5pa!?`ZaOEeZ2#t-(n(xW+}f|L&elYY8N8juEn@~%a_qL=X=-cpZ}rseJH#YP zTOa-CgOi;%uVWL`+n^Tf_nSS^?f%Ior?EGDor$7vA_o)n>5{&rr}h9^HPd^!L@x;o zi9Tk{C~M7owZ55~-)R9i?Bs=QmP(4>Vkb9l?J0GwZz+vyQzL&u&k&3Jnw&wS|lM#r!Fv5V-Bycm>7xlXn?p0gye7b)aukJCeWQEMzKb}}j4 z)sg(O*$8D#FU#NA8udoo>UC^gPuJNH&{&x!Yfv@$T$eEjLCH?3xTvwl^{2Z-CgG z#U+ftbzA}?TSwM-I8h5r`8GU^>v81563v6ckSymTBy3+7=|<*~a8b0rmA4y?)K~)b zVM&{jzj?(Tavsi@W4KD^#+5yFp)?Ad2LDMR#9RECMOgRL|Peb@^aH zcSW#t?a|IxyI&~&-zwj>_0i?S-^_n4d2L93x}r3WaemUuHR+uF9Q`N6l^t0!zKSNk z_v*UrdTKmxdu0Ev6~C2#4EUX<*E=AEBE@_a7h5+(I; zB`#T!uDv1~dBOc9+9Fxs(1}5!mTTnJjF2QUEonM`2f34qTyoj7mPJTg;)4#;i^kH& z>DWY$t#y>5ZSd1xzUH_@S{w^E*L?do_-WkK{ta%?vniX_I@X;plG+})S>w*#{^H){ z!{3S0By5{mp`_~Eq0D>tz3VjVoSW7G_Lwhm^0M=t*>Q0leXdI zoRouBbEEJ1QN<L@JS2^XfIyL!xG6PUP-TV#_&{VWDgIxE$^HvA2B0?IUY8+1XOS4;; zWh-t)&7?ZNu37l9K(q6+uwoVivTDs6qLbZ6JFByA<}V*!R!pL(M6I@G2jA#j?O4dG zZn-I*s`NlnCF~Z~xhss#i5e}sW~cc?vY5=8h(6U)chPME$jP%o)=vtEVfst-Tu0j7 z*vZy5ue}AkQ{1c*%?cjmm#85@F*=GQD{j=5^lwoX6X}oRKobU~aXwZAM`q;M=8EKV z2RTouQ7(q6S)05s_$IL({%zAwD43fflC{~3)aikosF|CkMt(?e8*Su?BGKdB_wR|C zm@(p}R@>oSY^2(ln`$dTj5&v$!Yw*yKc@&q%p8qG-`>-lW?#=-bO*WCmHdM(v+sihLUJTHKfwvv%L zOP!4*y{nwrOwSos`PFCi5!3zs8*M$TrTZq;dXohkxe<@N#+=2O=D%4MmRe*2uPO_z z2{lEN#FLwQ-^#bC1)%meapd3CM{+^mk**lh5lK^%htqa!rRK3{uGSUJDPcAP5hh6% zQ{!)GKZ;hTLAzorWgT^|Vis;Q`nh=L${3fpH&QjU`As|?cG5jf_#?9EDgCmpNk(QD z8MZwP%kV_E^lNiM>ue<{N4lypNSRW$yd;+`&YL{-^!b$E(DktDB}ch8j9Q;)Qg+fB zr-*?k>=Q|1Be6kVD~~*+dqvDL9IYe0UE;;^>CUD3zuilMmE3Y4iAE?ClT5kAPG-rx zQJ%ErKUgR#da(2T=FTr6cHd8f#LxMPTz$gLWfh-!!bLHgGd7VveRJ8%Zkpou6s+MESu=TH}s)@6OcP)|>?T zl8H#J&-WCORQ%tuq^_+bI~^N|yrgf#eJ&hZR==gl5vTad&*>Z2<{q#FFe6=a-wC4x zde4*INZ$VKG&lEpS@+z2TjCaWEF;afiDmm>0UvWRBj>eunE5DItrwA?!ZwOwSFKXi`% zfA>i`{{MFV@Yb(IZA0xgd}(>LaI?lGwhTAlZ`sQ~ReLU;PW>fSU%VdbPq%bV+dn_NbQ?`(+-AAm7SA@c2NDt7gd0BQNbDB6+l}qd-k`4pTgja?rMfHY zdh%Gukb~R0xqa^Us-bUCbHc}&pIdDv2R*n=sYNFuFH?3$J@cLH&ws(U<9`1ty07Fu(eN9WyyY0J^ID%6l`bnHw`TS)TFZ9!dh z%tP5&K5oTRK&VpfM>%roc+#HDHBit0mA0+!N!zfGuHVns@Z<6*8nYZ}Cbze`_r=V8 zB<>}-tnbYHYe$|fqohm3Ix0ERRkt zyPMP+d*QbshmPWqNsfJqHDGu$TH=DTQO%WH3$jtPjHZQY<@ zmj8s|LvdQjS2Y)C>wmKbjb-E>7R8j-Rr&9mTh@_~Vgk6S?#cIPUWp>`lU>_LQ#;n^ z|HKNKP0Avz?(dQ`i`(1tXXV?7|J6sbx4(TsUuEBrE{`eg?6#1_P4}pr+9hy9>s+p* znCJ`rb6 zZ>Q}u@>NdzYCrBH_X0!Z@NQ1cP4ZzD*NOTiFVSwpTMg8ZOxUC>G|{(|YHy|Ud!HP{ zw-HBf9sc9qtG|o9HknPLKC}mn`Vv7Z7SiaiwG7SAD4cQ?T}IPlK{swLZvAZjhl7*d z=JsNdOYLFFU7XF0c=GAy$W65DZJV0gKhJT)A|YKT%P;wXn|`sxv6KIoTWFfqDQ=vH zbHgn;wu)D;m$>ni-7+@_pUo}Qkj+R9J9V1d`^C-e?Qq+so}a-@Wlt;bOEsy|PxM#L!?lyM24M<=Nj){%E-I+E9@yCF#_I76sNCJC|XD;{m zJWpnRr%JeIq&G71@SD+4TtxY z!~WL#`g`@Q^LIIWSLZnS<&MR2r|ri1a&@8FjqVg)bw~W=sJ-0ao}$<2GTxYuyJ21( zbn~O-ODD^hPnK_r)^!FN{2)Yte|Ud5M$8AOYZlJ-iNZki@Ho`Rl1%S9sjp;rDNv3R8j{mDr1)F zX5+uUbRAlp9Cb}>IbFPTaZcCfKT4OdaqsBzzj5)*e+^(yjR1RK1z_#k|E+)l+l()E zGsB0ZUk>dX&hth7s{#AdNU#3sE{cWAI7#jhVMPoXDU^ZxI`G1=m@d2x4gg0W}L*5Jsm7j7g236OgK%vBwv{ikLA0wLn=FF z%HM4%vzyD-jmvQI$J0d-v^sTc-mxT`LaeM*Q^yMy%${2)&swrRy?1yI%wWuVwQBFM zs+~r-T4(!2z;=o;e{9i3Z`KZ_6W#CXvH*~l)^3eLrYu$xs1;nfJ#RD{of8f?uIu3E z4xR}={otvzx7W{5wab@q`&2qqPBI`J=8O2M;Y-nR0g20vM!YZ}y}r=&%2)SFB*qS6 z36C)03Zh0kkLvT~%3Qf)vAlRndIdi{z5=T6E|q7vx*c4NSmHxYSmLu`go3IBq)3)Z z`;n02ixH*b(s=f+^6XgFw9( zf45wVbOLACLHq zI+Vz1M@zkfVdWtt3yu9a6Vf70(9(~P7M=6_(Y$1esw?5-@J(Yn6;=bT;;u;5_c_>D zjt70Ah+<+BwA5u>-4o#=u%9b8%$6fd*M;b(%iE{Q9kVU0^#|B-og!6uMjmj|BNnK0 zBd$1s7u_!ai4Z-qv3x@y$@FRYoGM43-=DmFVC`^68}#j78t`{OMGNn`aLA}<$48X^xoRe>6KYO`D}e>bX6aXD5TA?3R)GxL^@ny*Z`TPC#l zzWU0bwNNe^EiOq|l3sihz8A*}A<2v@o=buXY_>il*qP7=2p%J#yp=L`d}B z93do8>QZxEJEwxtpH2ub1;x~T7_Cc>c)(Y;8T4vWBW;lFyb3<;`$<^Z+DS%!gznW9K3sgt8c6o zS5d9{@pN7AX@l0pC+4c*OYQb|q>`@|qAmj!AKNaq69ru`v#NrWAztN*b^zn^!_tm@ zHPSm|nVM%zQCW&^h@8n+Xgy1dIyYPa3GJ?{Y@796+2kOj_f8HtI(YtWf9cX(Qc}wh zqS1dkAk~)+9V~}^obgAcQJYP&xY)rdT_%b+15quH0lOcJOx>yA+&DFmIRBh*_e*+b zf>VX3g;migN{npPcTYGhcN!re5mvo*ysUaiAob7CLDJ`JcBoa(du%9{oJq(jy6DU8 zN#le-!O~fL-`b%PMNBT1Z1t1p^Vdc`c3$mJ@dc^JsAC-A>d~4^SZD)4^y<^o(k=|T zbS7=clqzmtH&eag4q7T^lbDdMk;&0?*lM@ttEuDCeHBH+(_tGmD&97G^^J2)VM62R zIN2dCkK@N$qe$!Z>nr&@wC5T*EcsHoB30=js$_T7lI4jU&5{Fak8h%}vZDyrwS z)54jreTN#j6FX*v#Ht&xR6aPUH!|Eqqa3tr0QkAn<;g|K=5odcpbA$jDlkS&jtMh= zuZzwJQ>Vud-d&Xn#vW@?77-W5#|ulVD`vhx7~AG67$m;YZo5K0Cv{5RrP7teTAV$I zk~eJO7Mr-d&_&7SxE>L!Ez233cVEzJ7@t3tUeC948HqE5p^Ke^lXOf{mUngS(xLp) zA(M8*=fvDCcrr15iw4C&cC?Q`PWM$x<>UdHdkJAmNGsS zHX0Hx3%Wv`=<0x3;ZZPr*0Y-@QC1uxC1XSEkwL;Y~~=8C=$V03pj8(`X0-8fkmS}&{X&ov&z z4_F4Uw97>flAwmxytJie$@GWXdsVlCP9yuYKM_v)CZ8c;p*~D@rs8^4t=g_A#a`0E z3`AWIRYH10r3p2NVnXfCrDb_ho#gIoQW=d6t7J9R0;gT`<;{dxN?6qpi#)@RPLyW} zbf?P>j}VQMydHR4uOwg85i6Aj>0*;9!m6!zNv7frafk}B5?_fTu>>=#xfW!hLTEwD z7#=8MlXiC2m-6+ZFSw*pVM{egrd}B-)i{MNmiCIJRhBG7Oga{gY6yjv&J2A-S5ne1 z>6$QOht;~(PKsA+r;j8^jppZK)&5{sGrI&Ces2W#D6TPg&f>{Es z1XmAJi8N8d+vY}#An9oNOPQq=bcv<*6)IhxwSg{DpgZFS_bl^+W8Wu-ZsiYMzlE_; zR9|&z8CP_cdr)1Lj-yh|mS-a(>CObI-C4lu30NAs?q>4U3m7U37>3^^e>5#BL2JUBE{em>v2ey@zP`XrX7!+dpGdOQ841m%O)#Ubh>P=2mu0S5 z$k8tZy^f88Vj3xX+=Y{U^`Q2AgEUuC?k&707s1re8wV%y1^=C{QDx|)UF17DhDW== zY?~RQM7YG8Lo5;K%GpHqFjlXK0kpuW0(N{*UfoVmjE#&R1;mEY*4)vgIW?GVM@JZ$#YY zDpzbKqT?@C&)ff;{<=Pcjw4frPRCk{D(Bkf;r_-^MSre+REXm8XE**9-%%E#JeLYu ze0}x_SGeq+=?X1$1TM0XGu$z$3m6-H7wauTiv({;U7a3-^J$C zXwvU4dG!YG31HMI#nr?!PV%K49wFq94OAK%UI!Ifh#i$Ee-WR5eWOt~(TP}ks+Z~9 zzDWfJ=sw!3cKI#ZG+k{^L2GhG2ej;W()#DAhiXt=PZv9!^ItrikLQow{!or@^)p)f zQXMS^UGyMaanYqKq3e=E8gvFKl9>-tF8j4F%o{TyfQ7Scg)RW~qm^1btEtQM=%B@rC zBLr6FV2sa+g)Xjw#eFRRGg{Dvi=5jyKo@$2H^cy}GG=!foD9!I$9CH%@)GUc);FT~ zcKs#3S7v{R^Fd_-81Yz}1L7PqFce^xwUDNHYN(^7Ht=y&Spmh+&#YYgy` zdfDN9c1x#I9`;Kq{gV8q-fMT+s9Odb?CmgY`MdpN)Ji)hFpU2S$7EASww=3fv%l1L zP^G)h##^YP1Uc;Rex<4TTcM5wejF&&U0YCi){!%85it=Z2s@4AdzJbc2h8*Cnno_bW0e{qtat<}KO?Y#50ztzb zX7akR1YNL%?Z!qT=83I=GWfB7j7=(JS^LoP7Y__*8nC^$2ciZMmGPrPvUOHAXegnW$l><{9y*Q=rGNF3 zdbVabX}O9Dk0Pidnf10lDYB@+cd7)R(h zrG@eXR_?VNepD+VSu*)duj4D#7tLLs_w_~CBfYW^rAz=ef=YCSD@yI-&7c*rLV`f0 zqs1mH;Rj=U)GK_ErRq+-_T(OOYiy;K)b zIE_CLlHnXb`)Ij(P?>y4+i4j`*qQaCTPrpW?7=2(k;bz&gbTo^XE$C2u-L;J1(j&A zQOOeJ-QMJLGHiTxVW2c%)j5J9`}a5Y)i|8G-wS5dKZ-gQeXR;<_Kbn8V-~<5EpkEM z&5tlUSNjMNQ?I4t4x2Pyf+*^AD6eVu%Ga`S9O?qvFf$Pz;3c%$Ii- z%g2l50@8P&Tt);kG&4dX5YilF@u$beOKf)Vs1qdEn$TI?I44LPCxnAs^u!;ey>5xC z$h8q@G9C;EMs!8o)IyKEhO(t%-Z)yf*BXJeP-g+g_q?1H!1j9ViPm8Z4VV;|x5^=L ztELp;iysoO&cSY5KVV5;z?-b89~ERx`exobW_Nm3su&w#_N@7Nj)<|6CLdZYql1?D zXCF{uy!n%DH9S*db`qYEG!toIj8d4HG2VrRtBzTxsP{`M=S|eP)?bIcS$7^`7T(g! zxXw4{%A1si3a&uzjeX@q`%^YIA#1bpr@;(%UcIgDyzBQeg{nE=?L- zaafE>w`~4&f4PIjW5<>881sh2kp>}xMcHnfF8{m*Y`_+-RBo)p%svVLu==VAoKQCs zx5(NQ6geIvy$^EpWX?TO?UPfTUTFz3d)9O3~6YW zh6W^H7s}khvfXx$i|eSMlJqskf*g(PAJ`E8=o`EdRXSl?c@uSzrm_lM#ErMe8f-iE zdkBe8WJ;(aH{wkqCfj*%c!FT8jUofs!c4(n?0MVk*0I-FM~a#uZnFX`jNNRyHXRu5 z4`3Ftqw$#Y9kAhTJI!|%2k3g&fc^Z0$Rt655D6qlGODyFP8B|(nbGGIS3ouJec=kI z#FfJdDzvcw`Ai3dtIn8ZEodPuaMe8~XhDljQuawUp$m|no2#3zHM(w})%25sG@v?J zg4Um%F26oizA;t)I4divqm)KTsp2JjS(E<*uR>IGENG!)P$Z&~BC{MR$UiEHSjSkB zGq7LNlzejKH0)S;OGV2L^u{J)I9AS~^0bK97Q0SQ2P9jo1eygcB~DWZx9L3loQE!V zL?UgbqAF2dH4&m}N`EI;y1Vbgg(7R(MKFeG#AL<*>;)KOD#z_?qGKr$H%OB;*NK9G z8D8@K3YgUF0;7Z3Aqw`={P6ao!m}7b8us~P8mnI0J8&$tomT1Oq#;w1>=>_xJK)+8_+G-E#P)Y*it-|8hf$RQhlluLd-rTped zxT$S=y%feiUL1admmxxnB30j4VG~;2OdvRMO`+JqEEgJ=o+?}&%}X}Y z&WN-Ta?r&lWlRWJn#@usO$pdaS0nAB?|07rE)|$P=cxhi4I%g^=C2}lvRs@g|2;_z zyTy1$!&XzT@sCj|;nb9^x6lZ3f9>UDQ_U?-!Awhtfeqi6Ny&fMQ*Pg{kHJS8Vb*jk zr1f_-9m6^PU`vn3Gz-9BGs_gop=Fw>o>=Rc1a0Ic=@Br)sBpp$2|O^1#WR+<{bj=m zWh#ELM>i>Ox5D9>VSx^sk%&dL0PG1iXH1&oG#up{`v*uvxFTOvP%WY_l}1ZMnJe@v zbivZNK0>QAhR~JQd1S=)ip@?^`kl0J#n*8QXi*7WlsOMcE#4kqnJ}y&6rzC2@xStE z-Ef^F%xbI!NSF{>ZWrB&y;LO-_A)J=7vN4e@@crs-#@Lzv2*JsYZ+Rqv_=tk)kw@0 zhM%;9mQZY(_J~^m4^7j~>&qYCQk^Ee;SiCjD^6u>N2d0azuzY0==TwFgJsRgHAL~4 zAPONU+cMaCW+S7{y`Io?oiof;yvn2jTjfp3TYRO}0KhD3ifv>QWt-oxYMPzqs2*8^x=WEbVlyk7+4ER{pPKjw`(26eF}Yhv%+ z`AXo=k83CaOMFd1)$|J3!W$nOqu#;0eMW=v?5{7CoJN%|J!N7Aa+g}hgLa%LWdH-D zi> z6r{0QPv^Xm##!x_3mo3C^a2&A(?D#$t@2itE%mub)+e|BRm^XhtLJQj#(@l9El6R--jGIU(AIPu_f}KxzqCh`QR43u!5#>k{qCv(+7dN+H>ALGGf_!sqrK z_$%N?iE$NQS&-v+=~TIV(36-RSIUz%iqI|vU~L|gc3^wVo5-MOY(R4B_p_`_TU-8{ zFP3kNV1uQEUOVUGx<7z=l61%K>tf)Xz6r13Y-^_=P>( zE0G%`P=YrG1+k-cuc%!7smi8iW8Mr~6|~gD+wUJy<8O{D>f=Jwb=MYrim2`7VLEcyssP1SE_g?V;mfh(3N+9Ef2%S&3s0)OmPUp6o!Ba_;4MaC1aT8}cCWZy>aXKlXPs^1 z;2AzRz>C(w52FU~gSs(+@3zzjm<2o%ZbHr;_TAZnec@2K>sa|YdEf`jng`2{d!7HW zw;l1O3y`lsOU{g5GJafQQLwPLnzd(Mq#Zm!=v;DlzD~yq$qs?4mmGom#TMpKX)j6i zfX$9|;El4Qx;KG?KR#MR3wV*cz$TaK92%QxX9wzMozAV)*|$EkS&Bys(IDXchb_t; zh$07a{PlBlW$iu<9A2@>$->?;-P1!brtFt1e!O?Y9x%koK9jMko$OfjMi4gqK+z(w zqup8#?NBEItCOwZNeqFI(2*5ZzH-IheyJZeX0Jnt+>P0j7}|m#1S;M$gqNIxL;Ymn z=iCTh5?2d&PzQT28$9Ynbe%x(14wuae$>G)Mu7K)BLZ&*d$gQ910`+92dFvia}#H1HtMR9ES%J~tP* zPPjp37P0WGXc;Jr zbeXX<)|WU)n52STbyP_&-!bK7LXgvI9Foj1Ck!ARw;Ib4u?zdb@qOGIRX zO{ZGdyFzP7i}ANYS^(oh?v;ue{>3v3>zt?$V7t5!F_;~)pQXglrlf*(-oVV%X~b~} zZ_9c%gBRX#yR7;k-b3z$Sro5T&@>v~ZrQn~lN^RL^v#&vb!>pQZUWEj!P{S)EdPS1 z4Q$ov)d^7mEX;g1bWUjej2&@EyA%v2q}5Rd?Wi1QhD#e+;JPM$X7hZ@w*XHRY+PPc zTw!k8qhYnSVBtZFoM+l1KwV*rLr{pnpYHmNU6 zmtXGJDk*Nmk*_~m&J)pbAK#t|*n7>rGLog=Cvn}@%5?lgWvN4Z~K4b^M8nS-fhG=;BOM_R!ALqx`L^hpuphDrF`rb<;)SPK*UJ#0|7? ztOBgb8q@(8Mg_0>;lW`em}LNKsG@0dno%~F0Cwy^`7x230qa~*`GPS^$tHtY%C9^s z_Zrx~_n>BB-ov8#ZP>-h`3&{xdR6ircQtqd1A;(>F2f>jmli}9-;P5)b5A*Yw|a0r zlE@%kM&PU~oOViq;@KTq= zIj*b86T4JK6S9UMr)33xum^#hYMt#WbQ6}u;dKzwBCQjFHD$--SI3VJ8QWzD>5D_H zLLJ*lcc5}cE?yO73xO$NkE9AE#`#$@uOY@5LVPO*axXP~W15u-3tIluV)+9csC_8N zDRbiF3CMln*g%WequnKn2ZZ?6Z$DaoxWD}59?`>+Ek zV1UQYlyLY{4<(ShD|buuUNwF!%OP&Lc2LVWDW6L)=9vheih)ysZdd8vSF^-?@enxW zQ84)7XTk4=LtHb-Og0twUtnA6BcsO8+JctN*oHs}#YezY64xx?< zTyobHuMJ@1VFjBR+vUnG-@Xlye!P-r#|++tH`oKVjBSxS){QfA%zUeL5AXz=BRWb} zAK`QFe@JpyweC@=8E6s0#X#<#W)tLS>>B8i1+G@QXG$+^o#Zy@;#KAiU}Bt~6^h51 zPdbIlRoL@nYmmEbuN3d=j5_J)dvtE$kaKlux#$Hg%8Ly-sKe5pI@Ix3K0GQn1WVXs zF2$1l>0_IRM-t0FV1h>V9GBh#crUf;v9lmFS+OPrMnqvFOF;@|H@SMelw2lu8|#b+_9qRk%RWQ1O+a zj&dB`bqK+a_Wl+=+t@haCasko6++{AIwIzw#PjA20>LZ>fhgV^2Z!E*=SBBmPeX~A zT`+@O?8gY*lGF?x12!|}O>13HjPwP+uQqVx0C_wnuU&fAWTUkr)3YKwy9!}goSA>I?H(x{}d(|5E}rxE{)OJxVNE+wuuqQ~F@@%#^)%PaTD zIAbzjs+62MzG)Y(tINSt{sc2W5k1Z=?ER6)0szCI);Dh}{Opv2ADxB0*6^dAVFfMh zcI`VVZ`fWBRfiQGM?~l#O_hn~9cU4m9Zt*LbJn^K5W4M!DWRU5;&O(%)w5;8yr!8* z_6odMrcm7y{16`$k572TiU)Of`Y8=jyc-*PAc|yh267dzV6Vfr0zbfO?A1|*#I1#S zNMDS`Kp5%(^>$MVW8_Bgt!^Izo)!ZnNiwD`ezr**uo2~UGjA0-tLVT z7Tz+;4`$v+YF3dOdDufE-oOn1NJ$7s2~mwVaRqE_vco0khk2D2@y2{a3pQ9m_n(dn zsvrk-NR~=RYvxUK#c0Q<2RurfqB}7A%CX@qjW>|PPM$1ZJ*N9C;Ee=@#LZ_6iums5 zJ>3@fSI_O@FuOGkutnR)+ph8 zGD^*KgOLkwLeA8|q1d*pMdgH|J!y~&b-2-|rZwA$tX1k<2ev))Ly#M5T9i$t9VL?%IS6+kX%<^Ra z31(h`TXiq~R3+?z8BkHG(i|lVwrK<{49sK!&-?V<)XoCDnR0DLgVx}bGWb!x+f1Y_ zP1uVk4SQf_@KmM_uBqc#sX(KF)T;z_gnZ}j6**_oJ!hOapUVTe0mrBK4Rc%vJRxvh zAG&%9K1%i1_h>xAi6wDYNn1`}APkutnc?a@nc8tz<{-}FQa#D|y1}EowvX$2K=h(}i6Vl^C*XH|AlJMq9O7p?flzvT6TN5J zCCmXCx^fyrAh2~0OH0MiI>uSr5s>yv@u<^6Li_5%z!--&uG4PtR&N;qGt9AEbF2+E z7=x=|MjfuaSx2U9#-3=?Vdq)+w6EO1DA+JDh8tZHc+>+M^RR3}ou<0tUOk|IB48U+ zhi|2k5~!$vTolhfcYrq(4`Tq!hy%9>Z@FMOOMLNjd|+oqu1fJ_W8Pl(#SW94jh}9D zs>IF?PKc~{mKulRtm-&ziQVNo^*{2kJ|>>}|J>&AtQ|oioVAWekD_w0#3qg05=fm2 ze?>dkXhH74j8!G~P3Z)(KoOM#FlM(=JWVE=v5-b-O;ci|S_G;Koqa2s%ohhL(88p3 zR=m~DlXIo;z36w&)hk;Hn3-N3GwafgSyjAF9VY~{(Ak-q8~_tzma-!!%1_DOd|MF? zMA0a&j3r3JA$x|ml!x%G_~I-tX+np%Mc>Y6EpZb)*uy~X3GdIz0lf3mx~1#rY4`TzKNNXcjfmf*;)b7nF-h{dq=Do4E`~zKlk0ua_pZQ*Z z7maFhoxCk7_j)9bxn_bo(i*HpYQWseY9cV$EVX0;7wy8;a>ZT7WpgxEid?b89npYP@m{lR3Nzg3ktS;`N%EghlqaUj z?A>A}i)KfFb!A)5Sd%p*QSlXh?NVdRje6V%XPz6~5@JC69K1PC0%J_A zGA#Y0jYHOF1|AIxG#YIw-w(mnp9<&AXy{LYr4=h0KAjWDx$gp2B4`1*c-Y7qn;*9!L$oX4QICRw8SWAbeh3=& zl_;JDvvRC|VfOy^Wcl^1vbaj*?sEL>LDSXlRg;lR*<2ytopXpwefTa-$5;H&x3x}L zY%J@(ru56l^K$D+48A;DzCWu_;lhFP)V}hAdwdhU;SqIa4C=&{4G6^{j8z-7Pj+z2 zHvaC~^2*)iDPlI~K#;Y72Z0;xPlKN&E<&g8xN6FpW>3o01LOoAv4<{tkirr;;ccJWS3W*fHXJXvc4)P;Ot9J5QWY#-4ehY8Gj}ihwOIZ|W`dG4;VI9=Xi)X)-f_*MvH ztq%AtCr~m7ftv6dW#>X5vQOtGVZt}%e*CfYp?gT;#g>#K2qAVoTW533vjasWk$b^h zcJ_wbDtji%BZ5^k3S;=W$ z=d=m;BYgdqGXGV{?4O@5|MXE|#;0N#^S8aspiX~0TK>&!`KvFMZMSHdoDj0sL6JZ* zW13yX+dBD{9l{|`RgrObtB~F2F|~% z%@H7O)HyRjPNTMa^wXJ9Hi?@NdT~lQXJ&QzcsNr&5~&!xIW44RV*l!7`JYdgonO^5 z^8DOSNTbBg+ETBjv825>0v;$Lq~GHb<`Gp*+)%bG&Z*$p&yGE8lQ;_<_oYUcxT(Yh z3cuxPVX2(6bCElSv1lC@t?T&JEK^dQ4)Xx7vS*55i8E&Knv=D5(E^-!L!RgJ!f|<) zfJZOzmJTY&?Xbl07om$1I}BRZIw}|kfw3Ljco?lSdx!iIo(s7n0^wo=JZT!pEopNT zt49*)MfZ3#gkOEh=@B4|L0y3S`G~^|W_gKTM&htkppFU#18Jn*sp}O68W^Gn8`y;h zl`$p)pKmdqQbrEyIN{R0K7d8>$kDN)i7^HDrJ{9zSe{v5roSa|!-o=-KK&4X@eI*j zH?lO~_kW)*H|;LBezDA1Cnad1P7$3{PJXi!Xw0;^S!J({0y6j``LubnFj- zIs&KYVEHD?lNxeIy?zPg(t`9Mbd+(jRE`qSd29<&^dP*w9O`hUW{G?q!pN&auFa0Y z7_WBB66w*H3b3Jal!DD;TPoR%w*{DmeF~Myc#!_R%+kjtjbvBrGFOV2OOp0O`^xW4 zm$P?iM*fe#D7)dGl>cp3Q6fhpT42c^PJAZ3*`ae}q>n}n@c#8_F^Qj*HLk+mBXYF^ zZZ!BMatn1GJc7MDw`*eM=1}KbPCoK#*yZ|W0&C`EGTy90=jFbEgci+$&G>R_`0dUk zOisp*9h&LJXzsw<7x$)Nz0KLGK`Jj1QSKg0Exf5cDgM2cQ6;0gdZOUAi)Mh zuh^O0sGy<&uRa#l&UBX-uH#q<^C;;ZN|>abw;b}+GwViJG;#qa%Xq<|NO;R8yrF?; zo#f757{!A((2CF@Za}CO2Z7(8FBqf=JO_RP&lUC*Z^xLqu+NQqRlg5kI1)2{@wSha zA1{{Mz9v0~D^6@YEay2_x=P1;7dhcP=wpu@;vd~o4*p?TyjN5+K;T18KU7{mAf%&j z!7Sw$YNlE={w=>+J1eaVb<4nObNZqVLk~w{$R9=S*dH%X@??$IMKFj!>#kYuI(0WW zz>Da$x}=ZZOtjze0FurL{X0KeRdPoMuSs8KU|EEm=`e6jm`7BMavD5MM%04~xgpd^ zd}58a9d@-q2y!o<(ocXbENLEx_49llc*BI8V3XZm-7C?Z9ILDf9Zq(lb%-9|@h;xW z`T5eK!d<*-gpRs4?NzOK1Ay@o26&7nKugFuYeyaG)WTb=azH{azw3$q6})M1u{0Ud zf&>`+W`5{N6%;AQim~_r7tZYht^F^mtT1S7|1cQ zpiErXsWWfVx)sQ!2UnEuJ)kF$2)X61cDH8y2iPOV_z^jk#)$^v_I#t#$%9GN<5oCtV^+AqRnYw`;kT0|@$Wg)1!dQ$t zukyVPv5w2@^Z6}TjIYm`0Y8zpsQM-kC|=6Y)#8S}ft+BoQKu!F)bEcMHi0z4;k!%2 z$4($aAQg$8X^fvGOQz$9+d5Zkl~eDh0(;JB)OD}-=n49qUFSdk~y zZ!bT%yIk5@em-CRhhc0v zY+(#13zH00fbhx|p~b1o@S)2Zm+gl6GXUm_&M?Mexy(nT*Bstgxd1JI31E0hz8YV! zXGr8y+wHEMF%*V}}x#7~>~>u;nVy=>`zJ5$moRNxIYqZCn% zF15@L5F+aAK#7j| ziPO@|SAG7?n?e^Ek7%~6Z707yUB0|nzWS(^sUT=Pw+H0-TV2yKkoo)(v2CQKX#{ee zx9=s2YuOS=JL~iaXn~wD(>Q|2jTT0@!1mZ(<-2?9bs8TkK^qMgILRA0&oJh*T}vaU ze(Y?>Jq@%3m0x^Yqs0|&l(5an`8T_ptUWh=T8a61PHcAv+Phum>|;sUQdN zChP%W19II+_o%baD|^cB`Lg-6R=-0aP(fEd75HH}8YKpPyCBVeS&HYOD<}#}T&?Z) zy?TJ^HM}Yz9K6j9)bR^Y2ZWS30`LR2${Q6wl^U&^wr>TS3$CDY_|yAcf4V6iK%#gT znktIG#vVka-|?pi9dG|JV+s!_3|sZE6}&~=P^S945E7rBM1#PWP6(CVdj$_?D)7$G667eMu7Nk8cu@D;y)|26t_HDZ^N}TU-40p_6h#t}32Xj!n$e4Q!6g`X&G-YmEd0MkfX~UtDknY%JQ0dre6T5F&Sm zO(9&IEaL^i=JiV)Y8?j`9xhGVx`tUQ;DpfeLb*h|0DD9Ksm(=Z}_ucCxJd zss;;>tsj(X8`%gmIaabI_*SxiyFIm<>y#6S;ZnI&v94?tv-!qYJgk2kjvlOBxe@_M z%kOp4Jkh^8>z5j7`2mPeB#k^$pXDDNzm80GaElUU94pLVkOoWq%qzx7q{GH;z{X4P zcDrXN*p%U0N3eleNFxIrulgjXLOLeW^lLA^65$Qf_)Q1S4<~IC+GR%xV_-uWJ7$$T z%Civtsvu_s0y%q|!?Dzv=R!aqpkz0>U}o$v+~7wnxoA#u9~qXL!|V1qPD zT%^FWqx{&_8DY@Sdwv`vTVEuzWZg69r4u>F7=N4$(TH2za3`9GX&EcnM{LI*E@Vl+cB@3}$I$6QWQ# zJ61{v(Wb3p>H3e2A3Ib6amQ|9e~t;vnn?9BzjsJb`#7SmvKP6VxNPJu({Q9~J{FS$ z1V--u_GI}ti{+r76&#lu(gI;+Z@qHDA``g-ynD1bM`Kl=L%b^WuosmJgu>4Wfi=y; z3O^4eQg&UUvm$q6UFuHuIX^252&YU1>@B)-#AVd)+2z9uAXI2aT-P4=%8}Pa^z2W; z$$wp*9sKkGY!LXuoE`%CW+RYzQUqG)P(SuurP2$A$&+{tt0>Njcitmkc3AMq!M7rP z7`m4_;9=Br>NpSFdINP-z>G6SdB5pG#~^T{pKeVf9KzU9!zKc0@eVWwR4Ty_mH>%* zHreeZt0F9Q%vATt0+874`!?Q1BE_aPNPr4^F{nfR;EnxbPy|bIteA$tf{jMC8!&lT zy`(=%BMF%x_a}aC&*vU2TbS$j!V-An7u-bMMC-H(Y>)eX{N1bs-d}#{lg4n&?zIXX zXAI;hW7Kc5Pf4ZmChAZRdOSAHnWW$8-}#;}X_$4=#&QQ~za^p*Yy$Wb%>f>N1=#Wz z|HC$UMo4?(xPEM%pO$#dQyY8?X1%@V0BlsEY}BQ13F;1Nm;jB3MiPgtA#vAy3;B6Z z!oryFv(M$UaO&3h?(#4ua)|Wod?_P+LaQ@oP3v^2-QeBteJ*%2jKM0HVFJ$&k9|2= zI}z2X8^G+Cjm94@iaOpN{El%U9MCj9WC}AY+lAR7IDr|_9XNqjO+-7Eb2z8;%jX{z zmK=&VvZ?)@Dgm}XKUwbE?gwLf&3Pp5VZ1G{wcllcGFC)z#HRLc!M!WL$9EVa{@vz z_PnpebM~;&F-pGv8Z&muPh_GFR4@Y-0K+qM-vxZhpv!A#Zo5BFo;rRQO{;SX3`{LZlndjNfM70P3#6p*pD0#LJq@|s#+E_ zV^*asQC#-Vs3CwsDF-CNiAz;;|PGULcAowDP z7~oxkI*(ET5BwnQkSF?i>6*1p=gkZ1@+x&s3ynl{P{;L)vc+%06^$4>P%=R#(oi{9 zz!gi2cNkR19eY-SUWO|y;2~dFHX-f%Rx?_7l}+Atj26#m>~Y@s*NaYlIIsjrsT^L? z%%sGbLK=-GZ4$XLnJazso_rqS0gU7GdrxTHI~;^@D?i2ipc1_JQv$X~oJz3=gamII z$pRjc8U$!h`r(s?P@i zCt4`;=U{v=*r!HjVp;5ZWP|OxugPP ztn%dnO7~3*t^CyN8&ni{RKUiJ^(@>9#>CtFaFYeC_I_5f;Z?^I5Y9!MV=a1n>{5j- zV^vB|rv^ENZ6oA}^EE#80g;;9tX-D15p^Tv*oRLNHM{wAdEQdVTW4gf~w`#4i;;F^b& z?z=Ewe(ms#3j2pHg<)huJhTM1cjJ`XSiroE1kK@Dd?+Hehi~NP(?T8fOEbEfI5Mfc ze=%QXy)=$E?W~{r``BoVK-L#ogFS+`*X}O6m|19pdXU37QNRXcE+bzP2%!suv<_j; zEiFMVc)Yjg%mlgc=A|;xHvqG;X@+a!I{ERDPs)dI94PYh3@6^X;%)JavUPZX?bwO( z(W&x;55C^1KfI@4bIDJJA!ym3NhWF18;?3Gf1-szsFhOOm zdL_J3GVMkA4M>%%J9s^h}l-{wRdj5HOP^{ z2st@Ef9O-&wIt~ccyoef%E|_B{6&pfNW^7W>P(1uvn5CqUN(BjTYOC03H?OtPU%d@VySE%FU@Dddat^2H*REtk9OtLfQnHHd>LW>&BA^1^; zQmCWkEtGV(D%Ltm?3=WBa+bvMo&(AozkOWy_#Ab{ILgL!RV?DxlxYJ1;q*2B| zj^U>gbX+_B0Rp+yJi}*p;KRJ_MJ6|XtuFug#@YeQ9Q`^fBVfh`qaz>NYPbiK1Qd@srtzqzC+4ucJTqK+L5m_`JceQ2et zV@8FfE~GI8V9_sblurWu*LduJ3Fpu8cNvp%%tw&5wl+zy*^}nMzh@1bWNmZ#U`u&% zX5gE?;n7wuL%wD#bOomnMY|e1Y^|bwWWq8IG`??=dBbzjYy8}{!*${)xC&q^$~!WV zx}dIyD8>uePrTq9bU8RwBs^=pjY7D@b&1DVO1Gh5P%LDV}%d_Rn2gubN|4J1-Ymk<(CW5R@7(qaqVXLHtwqPYNr13_VT;Q?po7uqwuD3y`Gqa0b3*vPs;runm!nfNg-#Wmc5-p z)&dfLLYVo&?BxbvbBssH+pz{fUUAYnHRObys`X6nTiXSiiedFzyNZj%A!xLq(1&Z*-pTMZF=A3~le+!jEnq+!WT~H zH;x%Z;9(iOkmAEG`+<8<2kMLzatk3Wfsj@r`CbMn1rjFu-T@r;X7 zJi_1?`Q`3uJzw+)2bs~6CvTY2GbCyJ;l8qay8MhYZ?0aP(F6Kk+$#b6)&BCi*(!7l z<;aLa<}aBJMkiTh#johjD3gEX9yiVoIOx?6N!$qAj-rZ=>V=t&Q7TaJYr^l$4`7yr z+c=k-u+2Uc$9g7}NZdd5eOn>nN!FlF>A8s9JhgL5QNge0%U|$wtMg@xS5#`ekVlKO zGzjdmECkY$FyU4m;x|sz8iyJ92rkk!^YV;i*g_hOfr?>NrE7NRGT2%)MhIZ`t6^;{M)`wX+4_bF*O3xJHCUnR=?EB`>t1r!p zw1w&N6evy$#XGi^?@jBm%zw2}N9I-5kKsn2Ueu%2p0-O>ww8cR30Q?{kjAtWGpg1x zMg(}n%^+Z_zE*BYMmM8_w#W^x zpbHCKWOTplb@)IP1Cq+stfB~r5>zsf1FFtdZR}8`VlOtKt72xl*3o@)`myrY#v*3# zxeT!H)S>7n0tPm5lsd9;nxN&sBF6l)!bEpCPyl=Plx|8z#NM(1IUCjIe}CRj`Pd!P_-6un(kRQn2PU;R?pyI#?D7#?YUGQZwpzObHLr z`sqDNH$6@UU~~EWgJm<)L}WEnUYag%?=3&#zMknay|rB4T&~?!Hf}Ae?=5$3)q`L3 zE_#g_A09MBrj!|?FP8hZO2G)Irs*I*tN&$i5?6vMm0E8jf=HQ3BQ{%>Sj#kl$_zyx zEl3&R?h?w(HHDY=?|QQY5#DZ_QdDq(hm9OBGpG6SYmY{)X7QdGlcH~WysB4P(vBzP zTSN(UF_LP_!c4%UWX(XhHNRd&=)RAHu3j79$0`7ks-G$A4_D zJmxj7uPu~YvofT~8Zw27?jrl)(I|BF6dWA#Dx}4rj#txy-^B2tbQ1~&Z-m5e?w7uO z#^9}=($MV2sd9CTK-zGxc*8$p??By@etPeLA2_V2cpFL@d(q%l~4v|aw~PIA1gJ|g+XAKKv+Ah&zf2MFEfpS8lD zO2nG7QRgM@gMNZWlNNDGk(Tr>lq=DI18E63; znsyby?keZjmvbAXY(NNa&uvr*d!R+{Xr9QJo#l5(@6`wqwBF#kVF$!jAOQ@3q3hpu z>533y6Qd&29DNrzy;=b~Sw4TVJbhf=6L}X=Hi!bPDBB@>Qbr$dvl;{el_!N4tA(lHC#ZA?}s z3*pqR&|;F&)8At^IyI(?fk4x-?n6o_kp^;9h<1># zTW=Y7U;IcjJlgE|A&nS6Ybu6wEz<5TDua4Y-H36(m zRPE`mQ(;?lte{jI?LaAkkiUD=?3u)ADRVR6Z6a-;3~6*d%0tht&@qy1cV-|^2c9+I zra{4Vy!AmrKw2hc9thw=^@p0E;YQi~1^4p%$I}<~YaK5!8_0d+X{^H*wC&vU%PQQZ zA;`fGS22c;0a!=_CkzKl@Wu`Z8YVT1xM{Zm(w@RUI%sE5`NBbM?wKxs%CqUF%ZBX| zE--uC?(cCwta~1o?k;=om2;f-4(xN(uJgi_Fhj~7Utd;#wSXU(Z72NZZueWt3){;v z3(lb_%}o9Jc>U2#vK*bU@TSt)-Hx1gfI8GHCh#O{Xdr1@=I&XTw2M5IpEshg2OVpI zM!@z2&!0qsn4)5w%ly}A-T1)0RPvQgzM^LFm6RAQq&Uvv^ex4!cwEE20pwn9p&GDF zcINd?; zFS`0+Rnd&q2)RL#n|C0u%MJeAvmnw88v}%kdI;EX*|)k}G*Nt7NFz1_s*siv@MwI} z!%|3tJxUB^gHlLiH_F9*`q?#PExfUL=k{{rRz+DXdtgEkx~LFn!5by`O;1VLmbOdH zkTUjMeXqy_Fh&PAeN7$2OBlR;>JNqAFZXIa_GQ+zbH5(<9ROP%J?CsKbb;0cw#u93 zPT-C27EEj=Wdk-A2wfrzfqbD7NEyg+(lYSetH|@CHrq=M5ZF+*rP=a-$YTm8V8eTc zG|FHm{*%dBoGRYY%@L^M(V3H;f&KB|x`3 z(`&v#a*vk5{3XZ*DwT1mrVGYm#;gKHoyJC8Wh~+bV^rWlzSX>GXuxQ6oXeeH*2Hb( zQXvh->Hq<4AI-fs%&rr<_P6vG{kx)P3IFyAx$s8G1Qv>VBTr0neuFUrDu<3q;`S+Z zhIWNIzD3vx8l5`Clbg*J9T;$ELC-`#KO_G{qz+}&l45#?QyEQSN{LkxqmVWlP4w8df*UpF*7m1-HnPZb0#9++4nNpnP+-oSTuvy}W3BGjcDnG9(jH z^Pki5q3z__^(6-Pg+d{=t_;r<57pki9{O$V=y;z982PP7zrddIqu0Mgt`%9c8gQa;J@AIUeb3`i5`D}-DR^^`hU*MzLGG;A7wM(e z&Z~TJP6dDNhtBb$Z`Uk$5t%b3 zkRzo(ajcVY&iRlgcZUzQI{`;?rd9DAs;y8wQP010Wgnm}IKvt2;4GXjXv5!$W(nnte#ctm#)xU^MT_xLU4V+U_ciGm-0 z^j)XdLKM^?JCN2@j`bcP@B-Nqz!Q7R2C(3Fbhi9|Jg$7bU}J9L&aLHFGi5j68N!cv znCEQusvsvjUjCHjOsow)C8X;RHKT(X$kj}Uz*`O^;6WWv5vCe``pt5fdF+y?-mB*?MG3VD;V%7>)`uWdIN8sgEUfZn%07Y05&qVqWbGGw zl+LXV^q__eeC(ZqP_qeuH)SU)_B>>GVNULq#2T{(#40R}hA2RyjMh;;XSw5q<7A#Z<&ZBjA?Ta(2@FN= z7InND>Y(x2mOn`>ckY(*`EQly)|ZRx%dhs9?`~IM|0QPFN4$ZMl?_c3b-=ddd#^$u z5SlmU<)us5)BL{t0fhnZc7x~FZrCd1*59iYxxjX0sw_-tDwcu6hPc$@Kc1s)~$1RJ$R7j zxK5#6q$U!iTLPiZw*)#n=a>QBEZ`IHaCtn9!4mh2Z#z%YX6;|8(Va9+`e~ysGv30l zZPEgDG3vCVc)vHLb-%FpOJ?wom+wNIUF~*Lmz5#7P8fqLN`wyGBM0)-zVfHc8aTE4 z;yw)=j_gxhw;RVat*M07L~Hjr(|flZ7U01cwsx%;W7KdbPjqpM!a1DpJrY3bl-sR) z?0L?9cI_?YrhigiMu@gD%{tt%wQPEjhjB^kWEL({Cy9%!Q3-Ovk4ART?aaQFo)Yk| zm${RR=g9GFhecgqoDj5{56_>7eV2*0z2!;!S-c@L=`2Wo@kIHLr^=r#l}~T=e4SQHODNEC+$zyLo2yx@2BsGj%%c+7JVJapZgf<11kYV1AJ9{J12qO)fet?N8< zgQ_?*V8TpRAKtaDN^bdgTXa*rQp8Z_N1gxZRC&fva=7dVN&p_3R*~~~7Vtn01G(?Q zo55qYlseQA&haFcSGNqW-XoAUY}ZgCLidQ1A%OHfawB)i!*cSG#K$)dkcPn?cKL42 znWBMc-MRH;>0X6%KVxl@*M$7X{kkds=UzPdb{u65;Sf6c))=tGy@oU)*A3W+1Np^6 z#u4zgq;)KG4Jr+CN91-YR!cGD=F3t%bfalRJ-1dR9cfZs+M zDT|PHUmLm}fj8EE6Ucd0KG>6$SCzLB}1@?RWLJ1 zm9*_^g%IG;$T=rkBUZ1P;Om`UpoMnG?C$ucuPGJGti(%G<>m*=cRm(aW;^+XEtl>0Bk?KOT3Yzdr`;@tcT=`Q2x4;I0R4Q*?u|O9Gw%gD&i;OhKFm&GL<5+#0o|UZ*8E~vZ&ek2P#tz%`y8|nb z^D!%O%c%1o?a1v2dv4?dU~etz;e=Va^wudY{XOrS?jen#1cyc3sAHjyO&lw(7Mrr5 zkse{J3V4s3y2m$5ufQgN;ZI>qm$v5`*rc6Tsi@=Vmp zJ;Q#(*7C|`g?23IWEi`KpB^T<*jxVop6X2b{Lwc(jlA=gifJ6HAJl>0V}4W!vkx!C znKG&2BY!e@hRs4Jt;0HRRK}YPKk-@dYZa(lW)UKnj1vKXS3}?xKfG)AQXNx(pDg)X zCgMj!R}@cj=d9iPK1h&8>!_rzvJWVl(!yaSFw?%?;T0fU5`_3!X2)JURX*ckEMtU) zmXxE?@mtuhY1t?IbP*H}mr5*0WKI;v&{e$Im4Fr+c-gaE2wfLID)apI!FFZpm2F{l3ka#%`hU7%`adf{)h4rGi|oNbv^h z7fxu3VJAy;zFqLJ-|%x#8Ch^g71D=?MfYG2b>ho1)D=|zgsO~!x5yoU_1|S+2NuOu z(Q{guixi;)V@gEt8V|dGv5MJ5?(Wm?yH(`CESB*F;5EbB^7fQf2FL74_bhr1zZ%i~ zBh(Smfm{@Cg`b^7bRmdwH1krUNs2| zVtLYrdk66**oO3D?pVKXdriN<~J@^ zF)h`l@*E_aU~9m< zc=KFpcdzh9UE=0f`BLU>;4OGq!bJi(cmpMwxS*-#l z%#tt}F*Xna!5C#=69!G$z-(1hHXbdz+KFz9n+6Wpoh^{#Mk>7OGks>?vZkqL-?5bg za;QEfK^>uMREsVyUP!~JW9;zC1LeETu|nGAh4LxCg*|tAfn3y#gP?MfGN(-d50{F2 zwI$lF+3?OA#3NHe3RUnE*RsbJ@=M(rmN?L#z+~A=?UIzJ$A!o zZ`JbhKjS&x++y>s@-G1?W6U;d4`%m68uvc<9%r}$LiVABPMPMGRo0nv`%Lqm?;IaK zwv+`qmWzlqetVIzsu}yKf3BCWfWa7G;8nSyY!h=I2MR->aK)?e6Gu7rr+DOG23opm z8i#E17B0X~`v)uEaE1hB1Gx%`dE+zhxz08ucxx)RaWWkSX@QM{3^@+DWiZ3co7JX~ zh895@{TLtGNdvINa;m`F3Gqf0hm%EW&?tDrjsB#$QSs&pw3^ZX3WGA zsofyQZ?Zg4);}aSn#I7|t$6H@?xBGgksB7?K<@T5rhT7~<9yz_R=izd=7@|(yXqfl z@f+Y>bSfB4dz>{$tPJr>&#f1AFiAVcdnf}tVV<=mA>(qVz;`YoZmv&qh$nsB4qB)<<_|L) zJZ)<5swd@cK`;x7a-B#VrH!3Cb$MeBLW%y63=w`K9%y8Y2{1Hv@a~kval5@n4U5f< zf*g_Cc^+YeC@q(`9DzgWXfEYRC3H6bxon<`zERpp20|V3`1p+0?StG?{6tHbq-+a- zsel=FsHHv#Z*JJGOaj0C%~j7D3D8=-)x%GRG@M)PF^6HiLTbsVyrAU4m$;ohhv=saR41L2o zX5&hPj(x@|#|e=tuGfW$xP8bv3de8P9K6AgWGdiMdb37l@}Ze*t&a5*sPmAv!8WW3 zZ!;@-0}o(}KrQDDag#qaavC^#v;=U|30>6i_E%fP249DO0e+s@ zte;K@)wo)b7JfvX){S6%W$o!%Gj@QkhaI*F#m3%^TZI|05w<;Ve;U0qY$M((avFGc z%btnWtZ#LU09`aT*u*L=@~z#kp*$lb5F(iQME445SX7P@0@;K;Wq|Yhp4a`BG)MbP zQ?@K$Sv6xz90!!mC>Z z5@!;qZgo_K#K9Hy$J<;LJMijb=8X#Nv^?(N!_g_-wt#zOo%#2+YrY<3!&vFP#t%P# zVn(oGgk%gzL5uEYeEJ=pbMB0sCQ0GVMj*$lEH3(xM>Z{#HA@4$>An1R0}~2%riLxZ zRhRmk6K5dp3zj%UZ|Q{6;O~9A{M9afFXl}7E_`?d?Y^lhZU{TVMdM=|mCH40Lnn=v zE^E?2NHetT#-#1FrfKj7MSCnt6_o(i_3gUKnhX%+OwqdPPoa)>4%J~}3A)a}a@Zm` zaewiKv_RuLH?wfdULQ3aAC4R!CYZ5Ayt&k$3bWxAXMG9bCXB_C2Ifed>rpM>30;7+ z)1=YP-~H8b&FT9k%|vj41K5H~RFOJ>@h2W5Zn0{Sq2I-t0q2%FCB`P~ zv5C=ZxY1}DbfIk2xhwFowdHsJP`bzUc*)D3zT|N0s3)Gl?E8Mc)@L6qU-lClh}O6n zA>mo12Jgn{y@?z7xi|l~H4V%r0owp$!3>;YlC_Z=g*V!loQOjNez0dk8s7raZe)GC z-6$3AR?fFGX22%WCb0QeR>3T?#-g}w{_#`pzGk#qz!Z^Mt{ZZLzTNg(D;I4Y)(IV!pJl$6HqYRC`Kj5OPw^FDQO4F z_w#eT^`UT8!8l<3TgHsdwBU#Zn|b5rMDgY__`%qfx$?79_1O+2Nf-;qhdxE>!%IgP zG9YM=d8XhTH^O*^l!y!D*0Oe&ez{kS(H-zZH*u=xnkRkLtAA-h*?^55z%TD*5`j^} z|FTiHFFo%CQJgybAbE*U2V*}*+zu!M26e=2k~N@WSn9j-(X^Z9rEJ(H2B%RrxW$vU zLNge{^)gou)a4oIMb zEviHWh2fNT_8Z>Vpq@18)$Qr1O`{vE10&p2(WQg&$Idbe=9T37Em1% zu_7aPp1t?Uo%zk*|FZsTtzs`i=Ob+&Z;WYsk8Rt(G2`)3>Y(KiY+_IhIqjM0S~*eh`x z*;7E`I5O#v4<7phc=_5MJk)6oHruv?s~dMtdg>A~MCf|a!`QK%HI=lT#-S_$ePctP zOt1aCwD4SIr99@eYj$<{T6XHDu$z%PeOpc0#H4s@)Y&>n6@dyl@AN6ip%it0cxeq` zkRf3}Ww*rgr}q|e9)CJ8QU^0`8|uhiA=e^PS3Zw?Lyp^aRrB1kC3LNgDUn8<1TXd) zevLHSk-GODN)}F)&XD+Z!o(a}Z(ZAcyuJI;{_1uIUSp|goxe`EGNx(RYdffO9iS`c zCTV;s;8n0NQdjx6YLJ_WwY6_&Y(0u-41PsmRM8G4?6*x48-b16fkpy&Hsmxgii!Y< zCCxq!)Eplpqt=p_Ts8C%N$Rj^hxvZ`ad<&I9Hge7{JB+>pNFt_?W9VQqjPzAGIH9@odA;X{KU4h`}?Rc8V!OJzX6+WES$(8i)3X|6bzpc$fOVRJv-9G_dJ6_18twd44 zLoED80*kuo7NdMo8Q*0e&u7uax98ZmdbwrTw)L>_fqU4N%BdTzZHpZ!5{DmY&$S+| zl*~21t}$G&K`uf!ZY!D?J-RZllTq%Nc!nNn#Eokt6CzCD(LI&Xrmij6E|@QO4k1W0 zz={Ygn3*BcR|=N$aw0a9@e7Z+!bxW#jXUQfj|H$5szHLBq#Sq72azWEpvU~oma1uo z*@BBt?zF1jDa?plgY8GV`>y$=-II&jOiGbBjJ4ME?G_%I7P)&m>5(ylcyB6{XrebN zUfYo=@{uR@)fH~AIe+Jg7H-2m^WEROMbMv@rpI5mibR}_pYyN+Gd3hjoG3}Jr#m+XlyMbX%dwhHM z!jA4Eex}}SX)&`vFVz@T{W4D(wwX0j0jb-IOd*O!y=ByuQKhS@&)onS8MeCygTm93 z8FnK|>jEJ-?K@bYuBy1z4$)(9sh{`2Ra`*m7H2CXcXJ#(nsb2X7BB9-Kqy?r;m=cP zc{<~Ro=Df5(xZz90vAjs-0W>OV~zb&ukWt#O!bWrj6%=C2;?PJ=LE)b&XO zmBq|ccE#rI-|w$t^4F3p_Di3SwLP4XgAyjsfzU^0h6s1?G0xjmHA|H)?U8Kp1@n4l3cR9g_+R6H^xxa@bHE#@1L4j5@I&2OySo2$UH30$x=Yt}|L&Ta z-}2p^HE)ARRxcQsAK6lV8W95?epX#t-kQ+h@njg#g&%P%0`0g>b*B>5`jgf|+7~i% z5N~|KBe^3gx?jz3QImK`fB?^pc#2+S_GVA6v@qnFcc)nH>Ba8x+3s%*rJpP3*@@kg z5gErbGK=Ls2fP?u>}lBZo$n6FO+)zE5a+@Vc((qEe-EAcg6?8!!yXOvqqwYJ*;oQ- z(#12fcBpGI=nBNtzR}n#J3DbTnhd%WF3W1;rs-bXJOb#k!W;I&Td!}yulBb#8638S zUu&%tbKvkIvBn(}s;IN(TnHzpc4$3pjfatnFB16TwDk1^md!LP2D&9*Lnj_c@$F5Vb!J4EmLWa_>(Unxxmw|sB* z&f|}+_b8jhh>M&xD|`0zkcv8!`8k^LK^_Xf^h~BE;Do$CSKYxc?=8{3-*{Du7wNNI zfFIo(dMJJo4gnSdC!ZZEp<{6UWS^p<8~~Tpkdy0$w^PHr7+IROEtA(>KAQ&(Z|fzB zCk!jyYrnVgRxk4ymc35TKC>%7d@@n3N6gr+LF;h!laV@@HPUX*4!IluME%kVwrUA- zMZ43~oz|sWji0~l^EbtFtuzFZyDx*Sk0u~D@^;ih_Ix~@P(wPU@%Dbc2WGx4E&nUL zO~JODxWgNhEp)wLvAc4y?`rfoYblJsLW0Jyj=FZ@$}eG-^m*!l0J@D3c2Vb-zelRO4q7e@Hd{RCUI&-m_-Qzu>+?r z0jyD|uKx=QHMske1I5F~`!YRUvev-h?qcJSj7a*{LQMk*u<7=tu)W*!mMN)e?Cu() zZK`CQ+JqFn7}oW_Cz+Eb-PG*abu~@m_x01w*Kb4=!}|RCiS6OkJ{4?z8A++1ms=9g z`k8OH{s@z}X3$N+Hnvg9&ewh1*YHo`ds&{8dm~%YnjW7O#ekZ8<2@Uo|%%nlD>F= z6msQaRX8;ETu*muA3L52;m;SwraR2f@l1Kj=pGKgt(JJ9tZi`^QwupLHt_Zgrq*8_ z@hLkOq-%`yv9>36RK6F4Gb4vn8o07zgo$kkJO@Re>W@bZ8-eF=m|&!2(B`aoGN8J7~Lo zB8$=>WVZCx3aH)0w~Tu_*j=)_@=mPnYV#_Xhs0dIJ4;?%((5^F>ET+)v~LYX8YtX& zb4CYiC0)62@PnfLHB7TE*W|?9wJkGMJLenT3V3oU>bDu$8y0Hurl&G0N@PL(e$OnX z-~X1(p@h97+e?=`q40C^9-O%y-T!f2<$s*HYv@wAbV4D&{fh0A^HalcO0J;wXav8d zbZ4~S0&*G-0gpQ0e`6fldEetf4tp-(FX#GdZGaVce2L_Z4HNtRV%bohNjrEf?72!! z1NRKzc?mg<&D}Z`=blbaSqv_l+cOr}{%5=ua`EwswB3_s-db*Xh+5%&5kj3v99wD7y}EHZx}zq#%#ay2R9Dwy%1$!w24*dV z(vYKR#LYK&>AtuNpta*AlO(LL{lvhZZ8fQHMH9&z6FS{tjk>2(Ve;393QL#h%+2+P zy}o6_9c><|bgt?b&gY(WRZ2RasaKxZHMvpP%bl>g6YHF3>Y{`g`X(B3wvZE5N#MLB ziIjO)e1orT-zHnG=^Q-Fj>q5l=FsUZsZz-8FRlCF+HQB$3{fsu1FQ{5lvg<%wW??X-{gMc&+t25?}T)VBSLOs(l3X<&PMZ!P~P zLVPjZbM!%Lu)Vme`=f=L@9Xk~&b9rs)s@ke>o61xR}v;*J7WG2V;>Az%~XUEde0|1 zfEL&;Ovzk>jT7i?CiU_s7aUy;Hv8W2XP0)y^qpW>cNA$N1yaMpQZuAgK+(dA{oNnW zcK`XBGMBrrtrV^jagCGT+U|9ohLCS24EF|)vuq?QTrJ2k$37`{ZjV?qNSxf7wyGaj47NGf}zBOFy+lGqtwo}_sZRhn2``Ws@ zdv&QgVc%%e^#nFwt8+?|BCdxz+yiM z##|*aoo-OGswQG3dh#t8CT=(sP5koON*(B|1piY*+$tj{cF?5hKGQFDu=|!Wk88`7 za`!={*{S{9*)22Onf2XECa<3D9^p5(w!XVkvXRRXZSNRywZzuR@+6-^X5Fbh%re(@H}Y=fnj!=HxZ^@cn97}id&Y&#~r#8KZ^Riur)6&v9V zDvdX0@f_YFYsrhQ=56f)?aP-t1_<$wcU@cXW~iObK)k@2Khm z?IUwj?<=DwGt6f*ExGH=@4_3pT2H+@0yfMv)e=Ok&0s*si4}XwH=cFZ(pUQ-Zzs00 zF0~t!IlibI^>ed|if>f5#KpOXS>N9Moy=I%H+kU9a#<>eI%TEv-G4RUg1Dtv*L`<$ zi-CL(-o!QYo4bEl>i)x0jYakSP`oQ2A#Q^78~1ic2jr;S%J^)*Xf<^Y*9>xxFH{+D zs|04>FWg*?7C-i<3S+J*+4QISkA9SGICpU#4|Qto8g(DW#XYvZJUZv#0*1PJf8Ro# zMBfwXeLj_3F>Iy+hhWz1X^&jZ(K@pC#hr8h8o#a#YjzMgHsF1(orvLsB2QIo0$4x> zMN;3Kw2{UYgLfy00Hp1G*^(*z+?|X{(P-jsQGbCQ&IiA)P|Saf&7DAzQ}q5^>d;u6 ztWbG!S9MaHO)$&C%26m^bR`9<8ogS(DSfHg$I`bl-3`mj&O-6#P05QUxWgf>`*2;i zbyHn@5Teo6&2>}Q*~9#wuu5dy?$gqS+iGyVGm$xYCY@qDI`fl*kP$o*U(Qe4142Wy z-QR0UKps`!n}-FBA6(a+nd$yvfA>#I)o9DJ*H(?a-!ACj-D&%bBnpZ+Bz;dCm~&|I zT@ym??fy23iXSqii7~I7t=V#L=t3EWgFs;0R!el?w~#n*zAq3mxIV=PcF^~@bbh

Pi6N=Lj6EZGjiM&Jns%6?+s10 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 literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga b/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga new file mode 100644 index 0000000000000000000000000000000000000000..2c12d52dac02f5bddb9ce9a445dc875647cb74ab GIT binary patch literal 230578 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

@}glz1WR5M#8fWFN?gT53# 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 J<9cqy{|k Date: Fri, 27 Mar 2020 14:10:32 +0100 Subject: [PATCH 073/213] Set alpha channel bits in the image descriptor during tga encoding --- src/ImageSharp/Formats/Tga/TgaEncoderCore.cs | 20 +++++++++++++++-- .../Formats/Tga/TgaEncoderTests.cs | 22 +++++++++---------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs index d5d7ce49eb..94bd367aa0 100644 --- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs @@ -78,8 +78,24 @@ namespace SixLabors.ImageSharp.Formats.Tga imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleBlackAndWhite : TgaImageType.BlackAndWhite; } - // If compression is used, set bit 5 of the image descriptor to indicate an left top origin. - byte imageDescriptor = (byte)(this.compression is TgaCompression.RunLength ? 32 : 0); + byte imageDescriptor = 0; + if (this.compression is TgaCompression.RunLength) + { + // If compression is used, set bit 5 of the image descriptor to indicate a left top origin. + imageDescriptor |= 0x20; + } + + if (this.bitsPerPixel is TgaBitsPerPixel.Pixel32) + { + // Indicate, that 8 bit are used for the alpha channel. + imageDescriptor |= 0x8; + } + + if (this.bitsPerPixel is TgaBitsPerPixel.Pixel16) + { + // Indicate, that 1 bit is used for the alpha channel. + imageDescriptor |= 0x1; + } var fileHeader = new TgaFileHeader( idLength: 0, diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs index f123370d11..00664de6ea 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [MemberData(nameof(TgaBitsPerPixelFiles))] - public void Encode_PreserveBitsPerPixel(string imagePath, TgaBitsPerPixel bmpBitsPerPixel) + public void TgaEncoder_PreserveBitsPerPixel(string imagePath, TgaBitsPerPixel bmpBitsPerPixel) { var options = new TgaEncoder(); @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [MemberData(nameof(TgaBitsPerPixelFiles))] - public void Encode_WithCompression_PreserveBitsPerPixel(string imagePath, TgaBitsPerPixel bmpBitsPerPixel) + public void TgaEncoder_WithCompression_PreserveBitsPerPixel(string imagePath, TgaBitsPerPixel bmpBitsPerPixel) { var options = new TgaEncoder() { @@ -80,52 +80,52 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void Encode_Bit8_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8) + public void TgaEncoder_Bit8_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8) // Using tolerant comparer here. The results from magick differ slightly. Maybe a different ToGrey method is used. The image looks otherwise ok. where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None, useExactComparer: false, compareTolerance: 0.03f); [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void Encode_Bit16_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16) + public void TgaEncoder_Bit16_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None, useExactComparer: false); [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void Encode_Bit24_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24) + public void TgaEncoder_Bit24_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None); [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void Encode_Bit32_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32) + public void TgaEncoder_Bit32_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None); [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void Encode_Bit8_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8) + public void TgaEncoder_Bit8_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8) // Using tolerant comparer here. The results from magick differ slightly. Maybe a different ToGrey method is used. The image looks otherwise ok. where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength, useExactComparer: false, compareTolerance: 0.03f); [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void Encode_Bit16_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16) + public void TgaEncoder_Bit16_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength, useExactComparer: false); [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void Encode_Bit24_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24) + public void TgaEncoder_Bit24_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength); [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void Encode_Bit32_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32) + public void TgaEncoder_Bit32_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32) where TPixel : unmanaged, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength); [Theory] [WithFile(Bit32, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel32)] [WithFile(Bit24, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel24)] - public void Encode_WorksWithDiscontiguousBuffers(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel) + public void TgaEncoder_WorksWithDiscontiguousBuffers(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel { provider.LimitAllocatorBufferCapacity().InPixelsSqrt(100); From 19ebfbdf5c09b3a4de48aff26dec733df9d8e98f Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 27 Mar 2020 16:49:04 +0100 Subject: [PATCH 074/213] Split tga alpha bits tests in 16 bit and 32 bit tests --- .../Formats/Tga/TgaDecoderTests.cs | 20 +++++++++++++++--- tests/ImageSharp.Tests/TestImages.cs | 2 +- tests/Images/External | 2 +- ...noalphabits.tga => 32bit_no_alphabits.tga} | Bin 4 files changed, 19 insertions(+), 5 deletions(-) rename tests/Images/Input/Tga/{32bit_noalphabits.tga => 32bit_no_alphabits.tga} (100%) diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index ec2621e65c..767b3b9546 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -7,6 +7,7 @@ using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; // ReSharper disable InconsistentNaming @@ -199,11 +200,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } [Theory] - [WithFile(NoAlphaBits32Bit, PixelTypes.Rgba32)] [WithFile(NoAlphaBits16Bit, PixelTypes.Rgba32)] - [WithFile(NoAlphaBits32BitRle, PixelTypes.Rgba32)] [WithFile(NoAlphaBits16BitRle, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_WhenAlphaBitsNotSet(TestImageProvider provider) + public void TgaDecoder_CanDecode_WhenAlphaBitsNotSet_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -213,6 +212,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(NoAlphaBits32Bit, PixelTypes.Rgba32)] + [WithFile(NoAlphaBits32BitRle, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WhenAlphaBitsNotSet(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + // Using here the reference output instead of the the reference decoder, + // because the reference decoder does not ignore the alpha data here. + image.DebugSave(provider); + image.CompareToReferenceOutput(ImageComparer.Exact, provider); + } + } + [Theory] [WithFile(Bit16, PixelTypes.Rgba32)] [WithFile(Bit24, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index db4c9a4483..3e2f4aa6f0 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -392,7 +392,7 @@ namespace SixLabors.ImageSharp.Tests public const string Bit24Pal = "Tga/targa_24bit_pal.tga"; public const string NoAlphaBits16Bit = "Tga/16bit_noalphabits.tga"; public const string NoAlphaBits16BitRle = "Tga/16bit_rle_noalphabits.tga"; - public const string NoAlphaBits32Bit = "Tga/32bit_noalphabits.tga"; + public const string NoAlphaBits32Bit = "Tga/32bit_no_alphabits.tga"; public const string NoAlphaBits32BitRle = "Tga/32bit_rle_no_alphabits.tga"; } } diff --git a/tests/Images/External b/tests/Images/External index d809551931..985e050aa7 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit d809551931858cd3873bad49d2fe915fddff7a26 +Subproject commit 985e050aa7ac11830ae7a178ca2283f8b6307e4c diff --git a/tests/Images/Input/Tga/32bit_noalphabits.tga b/tests/Images/Input/Tga/32bit_no_alphabits.tga similarity index 100% rename from tests/Images/Input/Tga/32bit_noalphabits.tga rename to tests/Images/Input/Tga/32bit_no_alphabits.tga From 54ccea32cc1d4678d76ce4cbb86907fe8b635a0e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 27 Mar 2020 21:46:25 +0000 Subject: [PATCH 075/213] Use Buffer2D throughout. Fix #1141 --- src/ImageSharp/Advanced/IPixelSource.cs | 15 +- .../Common/Extensions/ComparableExtensions.cs | 6 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 49 +++-- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 3 +- src/ImageSharp/Formats/Gif/LzwDecoder.cs | 24 ++- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 179 ++++++++---------- .../Quantization/IndexedImageFrame{TPixel}.cs | 25 ++- .../Quantization/QuantizeProcessor{TPixel}.cs | 7 +- .../Quantization/QuantizedImageTests.cs | 4 +- .../Quantization/WuQuantizerTests.cs | 38 ++-- 10 files changed, 172 insertions(+), 178 deletions(-) diff --git a/src/ImageSharp/Advanced/IPixelSource.cs b/src/ImageSharp/Advanced/IPixelSource.cs index d7162bc61f..f609b15d30 100644 --- a/src/ImageSharp/Advanced/IPixelSource.cs +++ b/src/ImageSharp/Advanced/IPixelSource.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Memory; @@ -6,6 +6,17 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Advanced { + ///

+ /// Encapsulates the basic properties and methods required to manipulate images. + /// + internal interface IPixelSource + { + /// + /// Gets the pixel buffer. + /// + Buffer2D PixelBuffer { get; } + } + /// /// Encapsulates the basic properties and methods required to manipulate images. /// @@ -18,4 +29,4 @@ namespace SixLabors.ImageSharp.Advanced ///
Buffer2D PixelBuffer { get; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs index 3c8570a2a4..1fe2a24c77 100644 --- a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp /// /// Restricts a to be within a specified range. /// - /// The The value to clamp. + /// The value to clamp. /// The minimum value. If value is less than min, min will be returned. /// The maximum value. If value is greater than max, max will be returned. /// @@ -137,4 +137,4 @@ namespace SixLabors.ImageSharp return value; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 02267de1ac..7919bc1489 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -353,7 +353,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadImageDescriptor(); IManagedByteBuffer localColorTable = null; - IManagedByteBuffer indices = null; + Buffer2D indices = null; try { // Determine the color table for this frame. If there is a local one, use it otherwise use the global color table. @@ -364,11 +364,11 @@ namespace SixLabors.ImageSharp.Formats.Gif this.stream.Read(localColorTable.Array, 0, length); } - indices = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(this.imageDescriptor.Width * this.imageDescriptor.Height, AllocationOptions.Clean); + indices = this.configuration.MemoryAllocator.Allocate2D(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean); - this.ReadFrameIndices(this.imageDescriptor, indices.GetSpan()); + this.ReadFrameIndices(indices); ReadOnlySpan colorTable = MemoryMarshal.Cast((localColorTable ?? this.globalColorTable).GetSpan()); - this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, this.imageDescriptor); + this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor); // Skip any remaining blocks this.SkipBlock(); @@ -383,16 +383,13 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Reads the frame indices marking the color to use for each pixel. /// - /// The . - /// The pixel array to write to. + /// The 2D pixel buffer to write to. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadFrameIndices(in GifImageDescriptor imageDescriptor, Span indices) + private void ReadFrameIndices(Buffer2D indices) { int dataSize = this.stream.ReadByte(); - using (var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream)) - { - lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize, indices); - } + using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream); + lzwDecoder.DecodePixels(dataSize, indices); } /// @@ -404,10 +401,9 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The indexed pixels. /// The color table containing the available colors. /// The - private void ReadFrameColors(ref Image image, ref ImageFrame previousFrame, Span indices, ReadOnlySpan colorTable, in GifImageDescriptor descriptor) + private void ReadFrameColors(ref Image image, ref ImageFrame previousFrame, Buffer2D indices, ReadOnlySpan colorTable, in GifImageDescriptor descriptor) where TPixel : unmanaged, IPixel { - ref byte indicesRef = ref MemoryMarshal.GetReference(indices); int imageWidth = this.logicalScreenDescriptor.Width; int imageHeight = this.logicalScreenDescriptor.Height; @@ -440,13 +436,20 @@ namespace SixLabors.ImageSharp.Formats.Gif this.RestoreToBackground(imageFrame); } - int i = 0; int interlacePass = 0; // The interlace pass int interlaceIncrement = 8; // The interlacing line increment int interlaceY = 0; // The current interlaced line - - for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) + int descriptorTop = descriptor.Top; + int descriptorBottom = descriptorTop + descriptor.Height; + int descriptorLeft = descriptor.Left; + int descriptorRight = descriptorLeft + descriptor.Width; + bool transFlag = this.graphicsControlExtension.TransparencyFlag; + byte transIndex = this.graphicsControlExtension.TransparencyIndex; + + for (int y = descriptorTop; y < descriptorBottom && y < imageHeight; y++) { + ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.GetRowSpan(y - descriptorTop)); + // Check if this image is interlaced. int writeY; // the target y offset to write to if (descriptor.InterlaceFlag) @@ -482,35 +485,29 @@ namespace SixLabors.ImageSharp.Formats.Gif } ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY)); - bool transFlag = this.graphicsControlExtension.TransparencyFlag; if (!transFlag) { // #403 The left + width value can be larger than the image width - for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) { - int index = Unsafe.Add(ref indicesRef, i); + int index = Unsafe.Add(ref indicesRowRef, x - descriptorLeft); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); Rgb24 rgb = colorTable[index]; pixel.FromRgb24(rgb); - - i++; } } else { - byte transIndex = this.graphicsControlExtension.TransparencyIndex; - for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) { - int index = Unsafe.Add(ref indicesRef, i); + int index = Unsafe.Add(ref indicesRowRef, x - descriptorLeft); if (transIndex != index) { ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); Rgb24 rgb = colorTable[index]; pixel.FromRgb24(rgb); } - - i++; } } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 8875409309..62410025c6 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -6,6 +6,7 @@ using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -471,7 +472,7 @@ namespace SixLabors.ImageSharp.Formats.Gif where TPixel : unmanaged, IPixel { using var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth); - encoder.Encode(image.GetPixelBufferSpan(), stream); + encoder.Encode(((IPixelSource)image).PixelBuffer, stream); } } } diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs index 0129db0e3d..8289ee75b0 100644 --- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs @@ -65,15 +65,15 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Decodes and decompresses all pixel indices from the stream. /// - /// The width of the pixel index array. - /// The height of the pixel index array. /// Size of the data. /// The pixel array to decode to. - public void DecodePixels(int width, int height, int dataSize, Span pixels) + public void DecodePixels(int dataSize, Buffer2D pixels) { Guard.MustBeLessThan(dataSize, int.MaxValue, nameof(dataSize)); // The resulting index table length. + int width = pixels.Width; + int height = pixels.Height; int length = width * height; // Calculate the clear code. The value of the clear code is 2 ^ dataSize @@ -105,17 +105,28 @@ namespace SixLabors.ImageSharp.Formats.Gif ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan()); ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan()); ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan()); - ref byte pixelsRef = ref MemoryMarshal.GetReference(pixels); for (code = 0; code < clearCode; code++) { Unsafe.Add(ref suffixRef, code) = (byte)code; } - Span buffer = stackalloc byte[255]; + Span buffer = stackalloc byte[byte.MaxValue]; + int y = 0; + int x = 0; + int rowMax = width; + ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(y)); while (xyz < length) { + // Reset row reference. + if (xyz == rowMax) + { + x = 0; + pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(++y)); + rowMax = (y * width) + width; + } + if (top == 0) { if (bits < codeSize) @@ -209,7 +220,8 @@ namespace SixLabors.ImageSharp.Formats.Gif top--; // Clear missing pixels - Unsafe.Add(ref pixelsRef, xyz++) = (byte)Unsafe.Add(ref pixelStackRef, top); + xyz++; + Unsafe.Add(ref pixelsRowRef, x++) = (byte)Unsafe.Add(ref pixelStackRef, top); } } diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index 056076bf01..516b82396d 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -41,13 +41,33 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private const int HashSize = 5003; + /// + /// The amount to shift each code. + /// + private const int HashShift = 4; + /// /// Mask used when shifting pixel values /// private static readonly int[] Masks = { - 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF + 0b0, + 0b1, + 0b11, + 0b111, + 0b1111, + 0b11111, + 0b111111, + 0b1111111, + 0b11111111, + 0b111111111, + 0b1111111111, + 0b11111111111, + 0b111111111111, + 0b1111111111111, + 0b11111111111111, + 0b111111111111111, + 0b1111111111111111 }; /// @@ -80,16 +100,6 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private readonly byte[] accumulators = new byte[256]; - /// - /// For dynamic table sizing - /// - private readonly int hsize = HashSize; - - /// - /// The current position within the pixelArray. - /// - private int position; - /// /// Number of bits/code /// @@ -177,15 +187,13 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Encodes and compresses the indexed pixels to the stream. /// - /// The span of indexed pixels. + /// The 2D buffer of indexed pixels. /// The stream to write to. - public void Encode(ReadOnlySpan indexedPixels, Stream stream) + public void Encode(Buffer2D indexedPixels, Stream stream) { // Write "initial code size" byte stream.WriteByte((byte)this.initialCodeSize); - this.position = 0; - // Compress and write the pixel data this.Compress(indexedPixels, this.initialCodeSize + 1, stream); @@ -199,10 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The number of bits /// See [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetMaxcode(int bitCount) - { - return (1 << bitCount) - 1; - } + private static int GetMaxcode(int bitCount) => (1 << bitCount) - 1; /// /// Add a character to the end of the current packet, and if it is 254 characters, @@ -239,25 +244,16 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Reset the code table. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ResetCodeTable() - { - this.hashTable.GetSpan().Fill(-1); - } + private void ResetCodeTable() => this.hashTable.GetSpan().Fill(-1); /// /// Compress the packets to the stream. /// - /// The span of indexed pixels. + /// The 2D buffer of indexed pixels. /// The initial bits. /// The stream to write to. - private void Compress(ReadOnlySpan indexedPixels, int initialBits, Stream stream) + private void Compress(Buffer2D indexedPixels, int initialBits, Stream stream) { - int fcode; - int c; - int ent; - int hsizeReg; - int hshift; - // Set up the globals: globalInitialBits - initial number of bits this.globalInitialBits = initialBits; @@ -265,92 +261,82 @@ namespace SixLabors.ImageSharp.Formats.Gif this.clearFlag = false; this.bitCount = this.globalInitialBits; this.maxCode = GetMaxcode(this.bitCount); - this.clearCode = 1 << (initialBits - 1); this.eofCode = this.clearCode + 1; this.freeEntry = this.clearCode + 2; + this.accumulatorCount = 0; // Clear packet - this.accumulatorCount = 0; // clear packet - - ent = this.NextPixel(indexedPixels); - - // TODO: PERF: It looks like hshift could be calculated once statically. - hshift = 0; - for (fcode = this.hsize; fcode < 65536; fcode *= 2) - { - ++hshift; - } - - hshift = 8 - hshift; // set hash code range bound - - hsizeReg = this.hsize; - - this.ResetCodeTable(); // clear hash table - + this.ResetCodeTable(); // Clear hash table this.Output(this.clearCode, stream); ref int hashTableRef = ref MemoryMarshal.GetReference(this.hashTable.GetSpan()); ref int codeTableRef = ref MemoryMarshal.GetReference(this.codeTable.GetSpan()); - while (this.position < indexedPixels.Length) - { - c = this.NextPixel(indexedPixels); + int entry = indexedPixels[0, 0]; - fcode = (c << MaxBits) + ent; - int i = (c << hshift) ^ ent /* = 0 */; + for (int y = 0; y < indexedPixels.Height; y++) + { + ref byte rowSpanRef = ref MemoryMarshal.GetReference(indexedPixels.GetRowSpan(y)); + int offsetX = y == 0 ? 1 : 0; - if (Unsafe.Add(ref hashTableRef, i) == fcode) + for (int x = offsetX; x < indexedPixels.Width; x++) { - ent = Unsafe.Add(ref codeTableRef, i); - continue; - } + int code = Unsafe.Add(ref rowSpanRef, x); + int freeCode = (code << MaxBits) + entry; + int hashIndex = (code << HashShift) ^ entry; - // Non-empty slot - if (Unsafe.Add(ref hashTableRef, i) >= 0) - { - int disp = 1; - if (i != 0) + if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode) { - disp = hsizeReg - i; + entry = Unsafe.Add(ref codeTableRef, hashIndex); + continue; } - do + // Non-empty slot + if (Unsafe.Add(ref hashTableRef, hashIndex) >= 0) { - if ((i -= disp) < 0) + int disp = 1; + if (hashIndex != 0) + { + disp = HashSize - hashIndex; + } + + do { - i += hsizeReg; + if ((hashIndex -= disp) < 0) + { + hashIndex += HashSize; + } + + if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode) + { + entry = Unsafe.Add(ref codeTableRef, hashIndex); + break; + } } + while (Unsafe.Add(ref hashTableRef, hashIndex) >= 0); - if (Unsafe.Add(ref hashTableRef, i) == fcode) + if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode) { - ent = Unsafe.Add(ref codeTableRef, i); - break; + continue; } } - while (Unsafe.Add(ref hashTableRef, i) >= 0); - if (Unsafe.Add(ref hashTableRef, i) == fcode) + this.Output(entry, stream); + entry = code; + if (this.freeEntry < MaxMaxCode) { - continue; + Unsafe.Add(ref codeTableRef, hashIndex) = this.freeEntry++; // code -> hashtable + Unsafe.Add(ref hashTableRef, hashIndex) = freeCode; + } + else + { + this.ClearBlock(stream); } - } - - this.Output(ent, stream); - ent = c; - if (this.freeEntry < MaxMaxCode) - { - Unsafe.Add(ref codeTableRef, i) = this.freeEntry++; // code -> hashtable - Unsafe.Add(ref hashTableRef, i) = fcode; - } - else - { - this.ClearBlock(stream); } } - // Put out the final code. - this.Output(ent, stream); - + // Output the final code. + this.Output(entry, stream); this.Output(this.eofCode, stream); } @@ -366,19 +352,6 @@ namespace SixLabors.ImageSharp.Formats.Gif this.accumulatorCount = 0; } - /// - /// Reads the next pixel from the image. - /// - /// The span of indexed pixels. - /// - /// The - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int NextPixel(ReadOnlySpan indexedPixels) - { - return indexedPixels[this.position++] & 0xFF; - } - /// /// Output the current code to the stream. /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs index ac737f452f..c271ce7425 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs @@ -4,6 +4,7 @@ using System; using System.Buffers; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -13,10 +14,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// A pixel-specific image frame where each pixel buffer value represents an index in a color palette. ///
/// The pixel format. - public sealed class IndexedImageFrame : IDisposable + public sealed class IndexedImageFrame : IPixelSource, IDisposable where TPixel : unmanaged, IPixel { - private IMemoryOwner pixelsOwner; + private Buffer2D pixelBuffer; private IMemoryOwner paletteOwner; private bool isDisposed; @@ -39,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.Configuration = configuration; this.Width = width; this.Height = height; - this.pixelsOwner = configuration.MemoryAllocator.AllocateManagedByteBuffer(width * height); + this.pixelBuffer = configuration.MemoryAllocator.Allocate2D(width, height); // Copy the palette over. We want the lifetime of this frame to be independant of any palette source. this.paletteOwner = configuration.MemoryAllocator.Allocate(palette.Length); @@ -67,16 +68,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ///
public ReadOnlyMemory Palette { get; } - /// - /// Gets the pixels of this . - /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlySpan GetPixelBufferSpan() => this.pixelsOwner.GetSpan(); // TODO: Buffer2D + /// + Buffer2D IPixelSource.PixelBuffer => this.pixelBuffer; /// /// Gets the representation of the pixels as a of contiguous memory - /// at row beginning from the the first pixel on that row. + /// at row beginning from the first pixel on that row. /// /// The row index in the pixel buffer. /// The pixel row as a . @@ -87,7 +84,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// Gets the representation of the pixels as a of contiguous memory - /// at row beginning from the the first pixel on that row. + /// at row beginning from the first pixel on that row. /// /// /// Note: Values written to this span are not sanitized against the palette length. @@ -98,7 +95,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The pixel row as a . [MethodImpl(InliningOptions.ShortMethod)] public Span GetWritablePixelRowSpanUnsafe(int rowIndex) - => this.pixelsOwner.GetSpan().Slice(rowIndex * this.Width, this.Width); + => this.pixelBuffer.GetRowSpan(rowIndex); /// public void Dispose() @@ -106,9 +103,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!this.isDisposed) { this.isDisposed = true; - this.pixelsOwner.Dispose(); + this.pixelBuffer.Dispose(); this.paletteOwner.Dispose(); - this.pixelsOwner = null; + this.pixelBuffer = null; this.paletteOwner = null; } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index 4583b7cff4..386caf1be3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -68,21 +68,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(in RowInterval rows) { - ReadOnlySpan quantizedPixelSpan = this.quantized.GetPixelBufferSpan(); ReadOnlySpan paletteSpan = this.quantized.Palette.Span; int offsetY = this.bounds.Top; int offsetX = this.bounds.Left; - int width = this.bounds.Width; for (int y = rows.Min; y < rows.Max; y++) { Span row = this.source.GetPixelRowSpan(y); - int rowStart = (y - offsetY) * width; + ReadOnlySpan quantizedRow = this.quantized.GetPixelRowSpan(y - offsetY); for (int x = this.bounds.Left; x < this.bounds.Right; x++) { - int i = rowStart + x - offsetX; - row[x] = paletteSpan[quantizedPixelSpan[i]]; + row[x] = paletteSpan[quantizedRow[x - offsetX]]; } } } diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 7e4eced8fc..7945741b01 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests using (IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { int index = this.GetTransparentIndex(quantized); - Assert.Equal(index, quantized.GetPixelBufferSpan()[0]); + Assert.Equal(index, quantized.GetPixelRowSpan(0)[0]); } } } @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests using (IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { int index = this.GetTransparentIndex(quantized); - Assert.Equal(index, quantized.GetPixelBufferSpan()[0]); + Assert.Equal(index, quantized.GetPixelRowSpan(0)[0]); } } } diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index 2a0a02d942..37b8cab60f 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -24,10 +24,11 @@ namespace SixLabors.ImageSharp.Tests.Quantization using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); - Assert.Equal(1, result.GetPixelBufferSpan().Length); + Assert.Equal(1, result.Width); + Assert.Equal(1, result.Height); Assert.Equal(Color.Black, (Color)result.Palette.Span[0]); - Assert.Equal(0, result.GetPixelBufferSpan()[0]); + Assert.Equal(0, result.GetPixelRowSpan(0)[0]); } [Fact] @@ -43,10 +44,11 @@ namespace SixLabors.ImageSharp.Tests.Quantization using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); - Assert.Equal(1, result.GetPixelBufferSpan().Length); + Assert.Equal(1, result.Width); + Assert.Equal(1, result.Height); Assert.Equal(default, result.Palette.Span[0]); - Assert.Equal(0, result.GetPixelBufferSpan()[0]); + Assert.Equal(0, result.GetPixelRowSpan(0)[0]); } [Fact] @@ -88,7 +90,8 @@ namespace SixLabors.ImageSharp.Tests.Quantization using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(256, result.Palette.Length); - Assert.Equal(256, result.GetPixelBufferSpan().Length); + Assert.Equal(1, result.Width); + Assert.Equal(256, result.Height); var actualImage = new Image(1, 256); @@ -97,17 +100,18 @@ namespace SixLabors.ImageSharp.Tests.Quantization for (int y = 0; y < actualImage.Height; y++) { Span row = actualImage.GetPixelRowSpan(y); - ReadOnlySpan quantizedPixelSpan = result.GetPixelBufferSpan(); - int yy = y * actualImage.Width; + ReadOnlySpan quantizedPixelSpan = result.GetPixelRowSpan(y); for (int x = 0; x < actualImage.Width; x++) { - int i = x + yy; - row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[i])]; + row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[x])]; } } - Assert.True(image.GetPixelSpan().SequenceEqual(actualImage.GetPixelSpan())); + for (int y = 0; y < image.Height; y++) + { + Assert.True(image.GetPixelRowSpan(y).SequenceEqual(actualImage.GetPixelRowSpan(y))); + } } [Theory] @@ -155,25 +159,27 @@ namespace SixLabors.ImageSharp.Tests.Quantization using (IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { Assert.Equal(4 * 8, result.Palette.Length); - Assert.Equal(256, result.GetPixelBufferSpan().Length); + Assert.Equal(1, result.Width); + Assert.Equal(256, result.Height); ReadOnlySpan paletteSpan = result.Palette.Span; int paletteCount = paletteSpan.Length - 1; for (int y = 0; y < actualImage.Height; y++) { Span row = actualImage.GetPixelRowSpan(y); - ReadOnlySpan quantizedPixelSpan = result.GetPixelBufferSpan(); - int yy = y * actualImage.Width; + ReadOnlySpan quantizedPixelSpan = result.GetPixelRowSpan(y); for (int x = 0; x < actualImage.Width; x++) { - int i = x + yy; - row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[i])]; + row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[x])]; } } } - Assert.True(expectedImage.GetPixelSpan().SequenceEqual(actualImage.GetPixelSpan())); + for (int y = 0; y < expectedImage.Height; y++) + { + Assert.True(expectedImage.GetPixelRowSpan(y).SequenceEqual(actualImage.GetPixelRowSpan(y))); + } } } } From edc4dda6b95100eb0be6ce7193c71243d1f7914d Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 28 Mar 2020 11:51:55 +0100 Subject: [PATCH 076/213] Use == instead of is --- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index bba04f98a4..cca34c9b0c 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Tga TgaThrowHelper.ThrowNotSupportedException($"Unknown tga colormap type {this.fileHeader.ColorMapType} found"); } - if (this.fileHeader.Width is 0 || this.fileHeader.Height is 0) + if (this.fileHeader.Width == 0 || this.fileHeader.Height == 0) { throw new UnknownImageFormatException("Width or height cannot be 0"); } @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Formats.Tga var image = Image.CreateUninitialized(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); Buffer2D pixels = image.GetRootFramePixelBuffer(); - if (this.fileHeader.ColorMapType is 1) + if (this.fileHeader.ColorMapType == 1) { if (this.fileHeader.CMapLength <= 0) { @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { this.currentStream.Read(palette.Array, this.fileHeader.CMapStart, colorMapSizeInBytes); - if (this.fileHeader.ImageType is TgaImageType.RleColorMapped) + if (this.fileHeader.ImageType == TgaImageType.RleColorMapped) { this.ReadPalettedRle( this.fileHeader.Width, @@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp.Formats.Tga } else { - var alpha = alphaBits is 0 ? byte.MaxValue : bufferSpan[idx + 3]; + var alpha = alphaBits == 0 ? byte.MaxValue : bufferSpan[idx + 3]; color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], (byte)alpha)); } @@ -445,7 +445,7 @@ namespace SixLabors.ImageSharp.Formats.Tga private void ReadBgra32(int width, int height, Buffer2D pixels, bool inverted) where TPixel : unmanaged, IPixel { - if (this.tgaMetadata.AlphaChannelBits is 8) + if (this.tgaMetadata.AlphaChannelBits == 8) { using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0)) { @@ -476,7 +476,7 @@ namespace SixLabors.ImageSharp.Formats.Tga for (int x = 0; x < width; x++) { int idx = x * 4; - var alpha = alphaBits is 0 ? byte.MaxValue : rowSpan[idx + 3]; + var alpha = alphaBits == 0 ? byte.MaxValue : rowSpan[idx + 3]; color.FromBgra32(new Bgra32(rowSpan[idx + 2], rowSpan[idx + 1], rowSpan[idx], (byte)alpha)); pixelRow[x] = color; } @@ -534,7 +534,7 @@ namespace SixLabors.ImageSharp.Formats.Tga } else { - var alpha = alphaBits is 0 ? byte.MaxValue : bufferSpan[idx + 3]; + var alpha = alphaBits == 0 ? byte.MaxValue : bufferSpan[idx + 3]; color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], (byte)alpha)); } @@ -579,7 +579,7 @@ namespace SixLabors.ImageSharp.Formats.Tga // The high bit of a run length packet is set to 1. int highBit = runLengthByte >> 7; - if (highBit is 1) + if (highBit == 1) { int runLength = runLengthByte & 127; this.currentStream.Read(pixel, 0, bytesPerPixel); From d915f48a50020b0a97649ded8a6e049d9559917a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 28 Mar 2020 16:23:29 +0000 Subject: [PATCH 077/213] Move IndexedImageFrame to root namespace. --- .../Processors/Quantization => }/IndexedImageFrame{TPixel}.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename src/ImageSharp/{Processing/Processors/Quantization => }/IndexedImageFrame{TPixel}.cs (98%) diff --git a/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs b/src/ImageSharp/IndexedImageFrame{TPixel}.cs similarity index 98% rename from src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs rename to src/ImageSharp/IndexedImageFrame{TPixel}.cs index c271ce7425..07451029e6 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs +++ b/src/ImageSharp/IndexedImageFrame{TPixel}.cs @@ -7,8 +7,9 @@ using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Quantization; -namespace SixLabors.ImageSharp.Processing.Processors.Quantization +namespace SixLabors.ImageSharp { /// /// A pixel-specific image frame where each pixel buffer value represents an index in a color palette. From 2cd942cfb8a790bf3945c5a5ad116f36b94a9299 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 28 Mar 2020 20:46:05 +0100 Subject: [PATCH 078/213] Add support for top right and bottom right image origin --- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 239 ++++++++++++++----- src/ImageSharp/Formats/Tga/TgaImageOrigin.cs | 28 +++ 2 files changed, 205 insertions(+), 62 deletions(-) create mode 100644 src/ImageSharp/Formats/Tga/TgaImageOrigin.cs diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index cca34c9b0c..270dfb22b6 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -17,6 +17,11 @@ namespace SixLabors.ImageSharp.Formats.Tga /// internal sealed class TgaDecoderCore { + /// + /// A scratch buffer to reduce allocations. + /// + private readonly byte[] buffer = new byte[4]; + /// /// The metadata. /// @@ -88,7 +93,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { try { - bool inverted = this.ReadFileHeader(stream); + TgaImageOrigin origin = this.ReadFileHeader(stream); this.currentStream.Skip(this.fileHeader.IdLength); // Parse the color map, if present. @@ -131,7 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Tga pixels, palette.Array, colorMapPixelSizeInBytes, - inverted); + origin); } else { @@ -141,7 +146,7 @@ namespace SixLabors.ImageSharp.Formats.Tga pixels, palette.Array, colorMapPixelSizeInBytes, - inverted); + origin); } } @@ -160,11 +165,11 @@ namespace SixLabors.ImageSharp.Formats.Tga case 8: if (this.fileHeader.ImageType.IsRunLengthEncoded()) { - this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 1, inverted); + this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 1, origin); } else { - this.ReadMonoChrome(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted); + this.ReadMonoChrome(this.fileHeader.Width, this.fileHeader.Height, pixels, origin); } break; @@ -173,11 +178,11 @@ namespace SixLabors.ImageSharp.Formats.Tga case 16: if (this.fileHeader.ImageType.IsRunLengthEncoded()) { - this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 2, inverted); + this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 2, origin); } else { - this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted); + this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, pixels, origin); } break; @@ -185,11 +190,11 @@ namespace SixLabors.ImageSharp.Formats.Tga case 24: if (this.fileHeader.ImageType.IsRunLengthEncoded()) { - this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3, inverted); + this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3, origin); } else { - this.ReadBgr24(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted); + this.ReadBgr24(this.fileHeader.Width, this.fileHeader.Height, pixels, origin); } break; @@ -197,11 +202,11 @@ namespace SixLabors.ImageSharp.Formats.Tga case 32: if (this.fileHeader.ImageType.IsRunLengthEncoded()) { - this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4, inverted); + this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4, origin); } else { - this.ReadBgra32(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted); + this.ReadBgra32(this.fileHeader.Width, this.fileHeader.Height, pixels, origin); } break; @@ -228,8 +233,8 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The to assign the palette to. /// The color palette. /// Color map size of one entry in bytes. - /// Indicates, if the origin of the image is top left rather the bottom left (the default). - private void ReadPaletted(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, bool inverted) + /// The image origin. + private void ReadPaletted(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(width, AllocationOptions.Clean)) @@ -240,7 +245,7 @@ namespace SixLabors.ImageSharp.Formats.Tga for (int y = 0; y < height; y++) { this.currentStream.Read(row); - int newY = Invert(y, height, inverted); + int newY = InvertY(y, height, origin); Span pixelRow = pixels.GetRowSpan(newY); switch (colorMapPixelSizeInBytes) { @@ -257,7 +262,8 @@ namespace SixLabors.ImageSharp.Formats.Tga } color.FromBgra5551(bgra); - pixelRow[x] = color; + int newX = InvertX(x, width, origin); + pixelRow[newX] = color; } break; @@ -267,7 +273,8 @@ namespace SixLabors.ImageSharp.Formats.Tga { int colorIndex = rowSpan[x]; color.FromBgr24(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); - pixelRow[x] = color; + int newX = InvertX(x, width, origin); + pixelRow[newX] = color; } break; @@ -277,7 +284,8 @@ namespace SixLabors.ImageSharp.Formats.Tga { int colorIndex = rowSpan[x]; color.FromBgra32(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); - pixelRow[x] = color; + int newX = InvertX(x, width, origin); + pixelRow[newX] = color; } break; @@ -295,8 +303,8 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The to assign the palette to. /// The color palette. /// Color map size of one entry in bytes. - /// Indicates, if the origin of the image is top left rather the bottom left (the default). - private void ReadPalettedRle(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, bool inverted) + /// The image origin. + private void ReadPalettedRle(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { int bytesPerPixel = 1; @@ -309,7 +317,7 @@ namespace SixLabors.ImageSharp.Formats.Tga for (int y = 0; y < height; y++) { - int newY = Invert(y, height, inverted); + int newY = InvertY(y, height, origin); Span pixelRow = pixels.GetRowSpan(newY); int rowStartIdx = y * width * bytesPerPixel; for (int x = 0; x < width; x++) @@ -348,7 +356,8 @@ namespace SixLabors.ImageSharp.Formats.Tga break; } - pixelRow[x] = color; + int newX = InvertX(x, width, origin); + pixelRow[newX] = color; } } } @@ -361,16 +370,36 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The width of the image. /// The height of the image. /// The to assign the palette to. - /// Indicates, if the origin of the image is top left rather the bottom left (the default). - private void ReadMonoChrome(int width, int height, Buffer2D pixels, bool inverted) + /// the image origin. + private void ReadMonoChrome(int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { + bool isXInverted = origin == TgaImageOrigin.BottomRight || origin == TgaImageOrigin.TopRight; + if (isXInverted) + { + TPixel color = default; + for (int y = 0; y < height; y++) + { + int newY = InvertY(y, height, origin); + Span pixelSpan = pixels.GetRowSpan(newY); + for (int x = 0; x < width; x++) + { + var pixelValue = (byte)this.currentStream.ReadByte(); + color.FromL8(Unsafe.As(ref pixelValue)); + int newX = InvertX(x, width, origin); + pixelSpan[newX] = color; + } + } + + return; + } + using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0)) { for (int y = 0; y < height; y++) { this.currentStream.Read(row); - int newY = Invert(y, height, inverted); + int newY = InvertY(y, height, origin); Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromL8Bytes(this.configuration, row.GetSpan(), pixelSpan, width); } @@ -384,29 +413,50 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The width of the image. /// The height of the image. /// The to assign the palette to. - /// Indicates, if the origin of the image is top left rather the bottom left (the default). - private void ReadBgra16(int width, int height, Buffer2D pixels, bool inverted) + /// The image origin. + private void ReadBgra16(int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { + TPixel color = default; + bool isXInverted = origin == TgaImageOrigin.BottomRight || origin == TgaImageOrigin.TopRight; using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0)) { for (int y = 0; y < height; y++) { - this.currentStream.Read(row); - Span rowSpan = row.GetSpan(); + int newY = InvertY(y, height, origin); + Span pixelSpan = pixels.GetRowSpan(newY); - if (!this.hasAlpha) + if (isXInverted) { - // We need to set the alpha component value to fully opaque. - for (int x = 1; x < rowSpan.Length; x += 2) + for (int x = 0; x < width; x++) { - rowSpan[x] = (byte)(rowSpan[x] | (1 << 7)); + this.currentStream.Read(this.buffer, 0, 2); + if (!this.hasAlpha) + { + this.buffer[1] |= 1 << 7; + } + + color.FromBgra5551(Unsafe.As(ref this.buffer[0])); + int newX = InvertX(x, width, origin); + pixelSpan[newX] = color; } } + else + { + this.currentStream.Read(row); + Span rowSpan = row.GetSpan(); - int newY = Invert(y, height, inverted); - Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width); + if (!this.hasAlpha) + { + // We need to set the alpha component value to fully opaque. + for (int x = 1; x < rowSpan.Length; x += 2) + { + rowSpan[x] |= (1 << 7); + } + } + + PixelOperations.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width); + } } } } @@ -418,16 +468,36 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The width of the image. /// The height of the image. /// The to assign the palette to. - /// Indicates, if the origin of the image is top left rather the bottom left (the default). - private void ReadBgr24(int width, int height, Buffer2D pixels, bool inverted) + /// The image origin. + private void ReadBgr24(int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { + bool isXInverted = origin == TgaImageOrigin.BottomRight || origin == TgaImageOrigin.TopRight; + if (isXInverted) + { + TPixel color = default; + for (int y = 0; y < height; y++) + { + int newY = InvertY(y, height, origin); + Span pixelSpan = pixels.GetRowSpan(newY); + for (int x = 0; x < width; x++) + { + this.currentStream.Read(this.buffer, 0, 3); + color.FromBgr24(Unsafe.As(ref this.buffer[0])); + int newX = InvertX(x, width, origin); + pixelSpan[newX] = color; + } + } + + return; + } + using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0)) { for (int y = 0; y < height; y++) { this.currentStream.Read(row); - int newY = Invert(y, height, inverted); + int newY = InvertY(y, height, origin); Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromBgr24Bytes(this.configuration, row.GetSpan(), pixelSpan, width); } @@ -441,18 +511,38 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The width of the image. /// The height of the image. /// The to assign the palette to. - /// Indicates, if the origin of the image is top left rather the bottom left (the default). - private void ReadBgra32(int width, int height, Buffer2D pixels, bool inverted) + /// The image origin. + private void ReadBgra32(int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { + TPixel color = default; if (this.tgaMetadata.AlphaChannelBits == 8) { + bool isXInverted = origin == TgaImageOrigin.BottomRight || origin == TgaImageOrigin.TopRight; + if (isXInverted) + { + for (int y = 0; y < height; y++) + { + int newY = InvertY(y, height, origin); + Span pixelSpan = pixels.GetRowSpan(newY); + for (int x = 0; x < width; x++) + { + this.currentStream.Read(this.buffer, 0, 4); + color.FromBgra32(Unsafe.As(ref this.buffer[0])); + int newX = InvertX(x, width, origin); + pixelSpan[newX] = color; + } + } + + return; + } + using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0)) { for (int y = 0; y < height; y++) { this.currentStream.Read(row); - int newY = Invert(y, height, inverted); + int newY = InvertY(y, height, origin); Span pixelSpan = pixels.GetRowSpan(newY); PixelOperations.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width); @@ -462,14 +552,13 @@ namespace SixLabors.ImageSharp.Formats.Tga return; } - TPixel color = default; var alphaBits = this.tgaMetadata.AlphaChannelBits; using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0)) { for (int y = 0; y < height; y++) { this.currentStream.Read(row); - int newY = Invert(y, height, inverted); + int newY = InvertY(y, height, origin); Span pixelRow = pixels.GetRowSpan(newY); Span rowSpan = row.GetSpan(); @@ -478,7 +567,8 @@ namespace SixLabors.ImageSharp.Formats.Tga int idx = x * 4; var alpha = alphaBits == 0 ? byte.MaxValue : rowSpan[idx + 3]; color.FromBgra32(new Bgra32(rowSpan[idx + 2], rowSpan[idx + 1], rowSpan[idx], (byte)alpha)); - pixelRow[x] = color; + int newX = InvertX(x, width, origin); + pixelRow[newX] = color; } } } @@ -492,8 +582,8 @@ namespace SixLabors.ImageSharp.Formats.Tga /// The height of the image. /// The to assign the palette to. /// The bytes per pixel. - /// Indicates, if the origin of the image is top left rather the bottom left (the default). - private void ReadRle(int width, int height, Buffer2D pixels, int bytesPerPixel, bool inverted) + /// The image origin. + private void ReadRle(int width, int height, Buffer2D pixels, int bytesPerPixel, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { TPixel color = default; @@ -504,7 +594,7 @@ namespace SixLabors.ImageSharp.Formats.Tga this.UncompressRle(width, height, bufferSpan, bytesPerPixel); for (int y = 0; y < height; y++) { - int newY = Invert(y, height, inverted); + int newY = InvertY(y, height, origin); Span pixelRow = pixels.GetRowSpan(newY); int rowStartIdx = y * width * bytesPerPixel; for (int x = 0; x < width; x++) @@ -541,7 +631,8 @@ namespace SixLabors.ImageSharp.Formats.Tga break; } - pixelRow[x] = color; + int newX = InvertX(x, width, origin); + pixelRow[newX] = color; } } } @@ -609,18 +700,48 @@ namespace SixLabors.ImageSharp.Formats.Tga /// Returns the y- value based on the given height. /// /// The y- value representing the current row. - /// The height of the bitmap. - /// Whether the bitmap is inverted. + /// The height of the image. + /// The image origin. + /// The representing the inverted value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int InvertY(int y, int height, TgaImageOrigin origin) + { + switch (origin) + { + case TgaImageOrigin.BottomLeft: + case TgaImageOrigin.BottomRight: + return height - y - 1; + default: + return y; + } + } + + /// + /// Returns the x- value based on the given width. + /// + /// The x- value representing the current column. + /// The width of the image. + /// The image origin. /// The representing the inverted value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int Invert(int y, int height, bool inverted) => (!inverted) ? height - y - 1 : y; + private static int InvertX(int x, int width, TgaImageOrigin origin) + { + switch (origin) + { + case TgaImageOrigin.TopRight: + case TgaImageOrigin.BottomRight: + return width - x - 1; + default: + return x; + } + } /// /// Reads the tga file header from the stream. /// /// The containing image data. - /// true, if the image origin is top left. - private bool ReadFileHeader(Stream stream) + /// The image origin. + private TgaImageOrigin ReadFileHeader(Stream stream) { this.currentStream = stream; @@ -641,15 +762,9 @@ namespace SixLabors.ImageSharp.Formats.Tga this.tgaMetadata.AlphaChannelBits = (byte)alphaBits; this.hasAlpha = alphaBits > 0; - // TODO: bits 4 and 5 describe the image origin. See spec page 9. bit 4 is currently ignored. - // Theoretically the origin could also be top right and bottom right. - // Bit at position 5 of the descriptor indicates, that the origin is top left instead of bottom left. - if ((this.fileHeader.ImageDescriptor & (1 << 5)) != 0) - { - return true; - } - - return false; + // Bits 4 and 5 describe the image origin. + var origin = (TgaImageOrigin)((this.fileHeader.ImageDescriptor & 0x30) >> 4); + return origin; } } } diff --git a/src/ImageSharp/Formats/Tga/TgaImageOrigin.cs b/src/ImageSharp/Formats/Tga/TgaImageOrigin.cs new file mode 100644 index 0000000000..06d7b59455 --- /dev/null +++ b/src/ImageSharp/Formats/Tga/TgaImageOrigin.cs @@ -0,0 +1,28 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Tga +{ + internal enum TgaImageOrigin + { + /// + /// Bottom left origin. + /// + BottomLeft = 0, + + /// + /// Bottom right origin. + /// + BottomRight = 1, + + /// + /// Top left origin. + /// + TopLeft = 2, + + /// + /// Top right origin. + /// + TopRight = 3, + } +} From baa98af0c78f0c29f7090631a984c0f428ae2193 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 29 Mar 2020 10:12:31 +0200 Subject: [PATCH 079/213] Add support for decoding 16bit monochrome images --- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 31 +++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 270dfb22b6..dd3b6a8218 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -436,7 +436,15 @@ namespace SixLabors.ImageSharp.Formats.Tga this.buffer[1] |= 1 << 7; } - color.FromBgra5551(Unsafe.As(ref this.buffer[0])); + if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite) + { + color.FromLa16(Unsafe.As(ref this.buffer[0])); + } + else + { + color.FromBgra5551(Unsafe.As(ref this.buffer[0])); + } + int newX = InvertX(x, width, origin); pixelSpan[newX] = color; } @@ -451,11 +459,18 @@ namespace SixLabors.ImageSharp.Formats.Tga // We need to set the alpha component value to fully opaque. for (int x = 1; x < rowSpan.Length; x += 2) { - rowSpan[x] |= (1 << 7); + rowSpan[x] |= 1 << 7; } } - PixelOperations.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width); + if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite) + { + PixelOperations.Instance.FromLa16Bytes(this.configuration, rowSpan, pixelSpan, width); + } + else + { + PixelOperations.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width); + } } } } @@ -612,7 +627,15 @@ namespace SixLabors.ImageSharp.Formats.Tga bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128); } - color.FromBgra5551(Unsafe.As(ref bufferSpan[idx])); + if (this.fileHeader.ImageType == TgaImageType.RleBlackAndWhite) + { + color.FromLa16(Unsafe.As(ref bufferSpan[idx])); + } + else + { + color.FromBgra5551(Unsafe.As(ref bufferSpan[idx])); + } + break; case 3: color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); From 41208b851d06d20b2bdd489c1cb0700b120d3465 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 29 Mar 2020 10:13:20 +0200 Subject: [PATCH 080/213] Add additional tests for monochrome images --- .../Formats/Tga/TgaDecoderTests.cs | 112 +++++++++++++++--- .../Formats/Tga/TgaEncoderTests.cs | 10 +- tests/ImageSharp.Tests/TestImages.cs | 11 +- tests/Images/Input/Tga/grayscale_a_LL.tga | Bin 0 -> 131116 bytes tests/Images/Input/Tga/grayscale_a_LR.tga | Bin 0 -> 131116 bytes tests/Images/Input/Tga/grayscale_a_UL.tga | Bin 0 -> 131116 bytes tests/Images/Input/Tga/grayscale_a_rle_LL.tga | Bin 0 -> 54102 bytes tests/Images/Input/Tga/grayscale_a_rle_LR.tga | Bin 0 -> 54237 bytes tests/Images/Input/Tga/grayscale_a_rle_UL.tga | Bin 0 -> 54295 bytes tests/Images/Input/Tga/grayscale_a_rle_UR.tga | Bin 0 -> 54052 bytes 10 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 tests/Images/Input/Tga/grayscale_a_LL.tga create mode 100644 tests/Images/Input/Tga/grayscale_a_LR.tga create mode 100644 tests/Images/Input/Tga/grayscale_a_UL.tga create mode 100644 tests/Images/Input/Tga/grayscale_a_rle_LL.tga create mode 100644 tests/Images/Input/Tga/grayscale_a_rle_LR.tga create mode 100644 tests/Images/Input/Tga/grayscale_a_rle_UL.tga create mode 100644 tests/Images/Input/Tga/grayscale_a_rle_UR.tga diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index 767b3b9546..2ce6eb3c2b 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -20,8 +20,104 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga private static TgaDecoder TgaDecoder => new TgaDecoder(); [Theory] - [WithFile(Grey, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_MonoChrome(TestImageProvider provider) + [WithFile(Gray8Bit, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Uncompressed_MonoChrome_8Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray8BitRle, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_8Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray16Bit, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Uncompressed_MonoChrome_16Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray16BitBottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Uncompressed_MonoChrome_WithBottomLeftOrigin_16Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray16BitBottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Uncompressed_MonoChrome_WithBottomRightOrigin_16Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray16BitRle, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_16Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray16BitRleBottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_WithBottomLeftOrigin_16Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray16BitRleBottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_WithBottomRightOrigin_16Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray16BitRleTopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_WithTopRightOrigin_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -127,18 +223,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } - [Theory] - [WithFile(GreyRle, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - using (Image image = provider.GetImage(TgaDecoder)) - { - image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); - } - } - [Theory] [WithFile(Bit16Rle, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_RunLengthEncoded_16Bit(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs index 00664de6ea..c6b8b71f99 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs @@ -25,10 +25,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga public static readonly TheoryData TgaBitsPerPixelFiles = new TheoryData { - { Grey, TgaBitsPerPixel.Pixel8 }, - { Bit32, TgaBitsPerPixel.Pixel32 }, - { Bit24, TgaBitsPerPixel.Pixel24 }, + { Gray8Bit, TgaBitsPerPixel.Pixel8 }, { Bit16, TgaBitsPerPixel.Pixel16 }, + { Bit24, TgaBitsPerPixel.Pixel24 }, + { Bit32, TgaBitsPerPixel.Pixel32 }, }; [Theory] @@ -37,14 +37,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga { var options = new TgaEncoder(); - TestFile testFile = TestFile.Create(imagePath); + var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { using (var memStream = new MemoryStream()) { input.Save(memStream, options); memStream.Position = 0; - using (Image output = Image.Load(memStream)) + using (var output = Image.Load(memStream)) { TgaMetadata meta = output.Metadata.GetTgaMetadata(); Assert.Equal(bmpBitsPerPixel, meta.BitsPerPixel); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 3e2f4aa6f0..0622222cf9 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -383,8 +383,15 @@ namespace SixLabors.ImageSharp.Tests public const string Bit24TopLeft = "Tga/targa_24bit_pal_origin_topleft.tga"; public const string Bit24RleTopLeft = "Tga/targa_24bit_rle_origin_topleft.tga"; public const string Bit32 = "Tga/targa_32bit.tga"; - public const string Grey = "Tga/targa_8bit.tga"; - public const string GreyRle = "Tga/targa_8bit_rle.tga"; + public const string Gray8Bit = "Tga/targa_8bit.tga"; + public const string Gray8BitRle = "Tga/targa_8bit_rle.tga"; + public const string Gray16Bit = "Tga/grayscale_a_UL.tga"; + public const string Gray16BitBottomLeft = "Tga/grayscale_a_LL.tga"; + public const string Gray16BitBottomRight = "Tga/grayscale_a_LR.tga"; + public const string Gray16BitRle = "Tga/grayscale_a_rle_UL.tga"; + public const string Gray16BitRleBottomLeft = "Tga/grayscale_a_rle_LL.tga"; + public const string Gray16BitRleBottomRight = "Tga/grayscale_a_rle_LR.tga"; + public const string Gray16BitRleTopRight = "Tga/grayscale_a_rle_UR.tga"; public const string Bit16Rle = "Tga/targa_16bit_rle.tga"; public const string Bit24Rle = "Tga/targa_24bit_rle.tga"; public const string Bit32Rle = "Tga/targa_32bit_rle.tga"; diff --git a/tests/Images/Input/Tga/grayscale_a_LL.tga b/tests/Images/Input/Tga/grayscale_a_LL.tga new file mode 100644 index 0000000000000000000000000000000000000000..2f9dbef635db3bc5806712324463422da156c150 GIT binary patch literal 131116 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 A|xZ8+T19*Qg^@$+S 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 literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/grayscale_a_LR.tga b/tests/Images/Input/Tga/grayscale_a_LR.tga new file mode 100644 index 0000000000000000000000000000000000000000..47f6b00b8539caf7c344fbeaa3e751cbcb658497 GIT binary patch literal 131116 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

EKjRc-d)#Sc@P{r#~66Du_h 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 BGV^^{9Dp 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

jNnn*R^`H&tFjIC`(LGDgwbuQR@lrMbeXVnX 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 literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/rgb_rle_LR.tga b/tests/Images/Input/Tga/rgb_rle_LR.tga new file mode 100644 index 0000000000000000000000000000000000000000..d79e6a2d5af237deb0b3357836e60de2178fb0bd GIT binary patch literal 73337 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 literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/rgb_rle_UR.tga b/tests/Images/Input/Tga/rgb_rle_UR.tga new file mode 100644 index 0000000000000000000000000000000000000000..24afcd9154572de35742e35a9aac7c721775cbe9 GIT binary patch literal 73086 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

;6}hKwlqAf7h5 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 literal 0 HcmV?d00001 From 4707966bfbeb3562bb0ec131787ee8fea75bfa00 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 29 Mar 2020 14:08:18 +0200 Subject: [PATCH 082/213] Update Magick.Net to 7.15.5 --- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 20 +++++++++---------- tests/Directory.Build.targets | 2 +- .../Formats/Tga/TgaTestUtils.cs | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index dd3b6a8218..c8e23532f6 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Tga ///

/// A scratch buffer to reduce allocations. /// - private readonly byte[] buffer = new byte[4]; + private readonly byte[] scratchBuffer = new byte[4]; /// /// The metadata. @@ -430,19 +430,19 @@ namespace SixLabors.ImageSharp.Formats.Tga { for (int x = 0; x < width; x++) { - this.currentStream.Read(this.buffer, 0, 2); + this.currentStream.Read(this.scratchBuffer, 0, 2); if (!this.hasAlpha) { - this.buffer[1] |= 1 << 7; + this.scratchBuffer[1] |= 1 << 7; } if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite) { - color.FromLa16(Unsafe.As(ref this.buffer[0])); + color.FromLa16(Unsafe.As(ref this.scratchBuffer[0])); } else { - color.FromBgra5551(Unsafe.As(ref this.buffer[0])); + color.FromBgra5551(Unsafe.As(ref this.scratchBuffer[0])); } int newX = InvertX(x, width, origin); @@ -497,8 +497,8 @@ namespace SixLabors.ImageSharp.Formats.Tga Span pixelSpan = pixels.GetRowSpan(newY); for (int x = 0; x < width; x++) { - this.currentStream.Read(this.buffer, 0, 3); - color.FromBgr24(Unsafe.As(ref this.buffer[0])); + this.currentStream.Read(this.scratchBuffer, 0, 3); + color.FromBgr24(Unsafe.As(ref this.scratchBuffer[0])); int newX = InvertX(x, width, origin); pixelSpan[newX] = color; } @@ -531,9 +531,9 @@ namespace SixLabors.ImageSharp.Formats.Tga where TPixel : unmanaged, IPixel { TPixel color = default; + bool isXInverted = origin == TgaImageOrigin.BottomRight || origin == TgaImageOrigin.TopRight; if (this.tgaMetadata.AlphaChannelBits == 8) { - bool isXInverted = origin == TgaImageOrigin.BottomRight || origin == TgaImageOrigin.TopRight; if (isXInverted) { for (int y = 0; y < height; y++) @@ -542,8 +542,8 @@ namespace SixLabors.ImageSharp.Formats.Tga Span pixelSpan = pixels.GetRowSpan(newY); for (int x = 0; x < width; x++) { - this.currentStream.Read(this.buffer, 0, 4); - color.FromBgra32(Unsafe.As(ref this.buffer[0])); + this.currentStream.Read(this.scratchBuffer, 0, 4); + color.FromBgra32(Unsafe.As(ref this.scratchBuffer[0])); int newX = InvertX(x, width, origin); pixelSpan[newX] = color; } diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index 3c3b3b5ece..df153c08bb 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -29,7 +29,7 @@ - + diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs index cb3986b1fb..c69cf2f20b 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs @@ -44,6 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga { using (var magickImage = new MagickImage(fileInfo)) { + magickImage.AutoOrient(); var result = new Image(configuration, magickImage.Width, magickImage.Height); Span resultPixels = result.GetPixelSpan(); From 11bf5bfbdca141025baa29f4e1e18c52f932ff2b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 29 Mar 2020 14:15:21 +0200 Subject: [PATCH 083/213] Simplify ReadBgra32 --- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index c8e23532f6..e9e7ce7190 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -532,26 +532,8 @@ namespace SixLabors.ImageSharp.Formats.Tga { TPixel color = default; bool isXInverted = origin == TgaImageOrigin.BottomRight || origin == TgaImageOrigin.TopRight; - if (this.tgaMetadata.AlphaChannelBits == 8) + if (this.tgaMetadata.AlphaChannelBits == 8 && !isXInverted) { - if (isXInverted) - { - for (int y = 0; y < height; y++) - { - int newY = InvertY(y, height, origin); - Span pixelSpan = pixels.GetRowSpan(newY); - for (int x = 0; x < width; x++) - { - this.currentStream.Read(this.scratchBuffer, 0, 4); - color.FromBgra32(Unsafe.As(ref this.scratchBuffer[0])); - int newX = InvertX(x, width, origin); - pixelSpan[newX] = color; - } - } - - return; - } - using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0)) { for (int y = 0; y < height; y++) From e99204eac64f74ab1c48f6adb421c56764f4c1cd Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 29 Mar 2020 19:15:25 +0200 Subject: [PATCH 084/213] Update external for the 16bit gray tga images --- .../Formats/Tga/TgaDecoderTests.cs | 69 ++++++++++++------- tests/Images/External | 2 +- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index 5bfb38b742..d9f51701e6 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Gray8Bit, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_MonoChrome_8Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_Gray_8Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Gray8BitRle, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_8Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_8Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -45,91 +45,112 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Gray16Bit, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_MonoChrome_16Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_Gray_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + + // Using here the reference output instead of the the reference decoder, + // because the reference decoder output seems not to be correct for 16bit gray images. + image.CompareToReferenceOutput(ImageComparer.Exact, provider); } } [Theory] [WithFile(Gray16BitBottomLeft, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_MonoChrome_WithBottomLeftOrigin_16Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_Gray_WithBottomLeftOrigin_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + + // Using here the reference output instead of the the reference decoder, + // because the reference decoder output seems not to be correct for 16bit gray images. + image.CompareToReferenceOutput(ImageComparer.Exact, provider); } } [Theory] [WithFile(Gray16BitBottomRight, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_MonoChrome_WithBottomRightOrigin_16Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_Gray_WithBottomRightOrigin_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + + // Using here the reference output instead of the the reference decoder, + // because the reference decoder output seems not to be correct for 16bit gray images. + image.CompareToReferenceOutput(ImageComparer.Exact, provider); } } [Theory] [WithFile(Gray16BitRle, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_16Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + + // Using here the reference output instead of the the reference decoder, + // because the reference decoder output seems not to be correct for 16bit gray images. + image.CompareToReferenceOutput(ImageComparer.Exact, provider); } } [Theory] [WithFile(Gray16BitRleBottomLeft, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_WithBottomLeftOrigin_16Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithBottomLeftOrigin_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + + // Using here the reference output instead of the the reference decoder, + // because the reference decoder output seems not to be correct for 16bit gray images. + image.CompareToReferenceOutput(ImageComparer.Exact, provider); } } [Theory] [WithFile(Gray16BitRleBottomRight, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_WithBottomRightOrigin_16Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithBottomRightOrigin_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + + // Using here the reference output instead of the the reference decoder, + // because the reference decoder output seems not to be correct for 16bit gray images. + image.CompareToReferenceOutput(ImageComparer.Exact, provider); } } [Theory] [WithFile(Gray16BitRleTopRight, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome_WithTopRightOrigin_16Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_WithTopRightOrigin_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) { image.DebugSave(provider); - TgaTestUtils.CompareWithReferenceDecoder(provider, image); + + // Using here the reference output instead of the the reference decoder, + // because the reference decoder output seems not to be correct for 16bit gray images. + image.CompareToReferenceOutput(ImageComparer.Exact, provider); } } [Theory] [WithFile(Bit15, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_15Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_15Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -153,7 +174,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit16, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_16Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -177,7 +198,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit24, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_24Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_24Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -189,7 +210,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit24TopRight, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_WithTopRightOrigin_24Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_WithTopRightOrigin_24Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -201,7 +222,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit24BottomRight, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_WithBottomRightOrigin_24Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_WithBottomRightOrigin_24Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -261,7 +282,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit32, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_32Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_32Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -273,7 +294,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit32BottomRight, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_WithBottomRightOrigin_32Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_WithBottomRightOrigin_32Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -285,7 +306,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit32TopRight, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_Uncompressed_WithTopRightOrigin_32Bit(TestImageProvider provider) + public void TgaDecoder_CanDecode_WithTopRightOrigin_32Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) diff --git a/tests/Images/External b/tests/Images/External index 985e050aa7..6f81d7a95e 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 985e050aa7ac11830ae7a178ca2283f8b6307e4c +Subproject commit 6f81d7a95e285b1449efd4319a5cc7b071dec679 From 944e68fb19a05d760b79ab5aa6b2a14964de562e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 29 Mar 2020 18:49:45 +0100 Subject: [PATCH 085/213] Make deflater constants internal --- src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs | 4 +--- src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs index 67e8c6900b..a3a87a32f8 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs @@ -3,15 +3,13 @@ // using System; -using System.Collections.Generic; -using System.Text; namespace SixLabors.ImageSharp.Formats.Png.Zlib { /// /// This class contains constants used for deflation. /// - public static class DeflaterConstants + internal static class DeflaterConstants { /// /// Set to true to enable debugging diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs index 7be794b5e7..1a8bb4ab04 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// /// Strategies for deflater /// - public enum DeflateStrategy + internal enum DeflateStrategy { /// /// The default strategy From 7123b302b82b3e9895bb4f6c53ee572ab32d068a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 29 Mar 2020 18:49:57 +0100 Subject: [PATCH 086/213] Move GeometryUtilities --- src/ImageSharp/GeometryUtilities.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/GeometryUtilities.cs b/src/ImageSharp/GeometryUtilities.cs index 43c46f1812..00fa5b97f1 100644 --- a/src/ImageSharp/GeometryUtilities.cs +++ b/src/ImageSharp/GeometryUtilities.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; -namespace SixLabors +namespace SixLabors.ImageSharp { /// /// Utility class for common geometric functions. @@ -31,4 +31,4 @@ namespace SixLabors [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float RadianToDegree(float radian) => radian / (MathF.PI / 180F); } -} \ No newline at end of file +} From ac7dee0e712fb16e5a8f703ed0466e180daf387b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 29 Mar 2020 22:38:13 +0100 Subject: [PATCH 087/213] Update colorspace namespaces --- src/ImageSharp/ColorSpaces/Companding/LCompanding.cs | 4 ++-- .../ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs | 3 +-- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs | 4 +--- .../ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs | 4 +--- .../ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs | 6 ++---- .../ColorSpaces/Conversion/ColorSpaceConverter.cs | 5 ++--- .../ColorSpaces/Conversion/ColorSpaceConverterOptions.cs | 5 ++--- .../Implementation}/CieXyChromaticityCoordinates.cs | 6 +++--- .../Implementation/Converters/CIeLchToCieLabConverter.cs | 2 +- .../Implementation/Converters/CieLabToCieLchConverter.cs | 6 +++--- .../Implementation/Converters/CieLabToCieXyzConverter.cs | 6 +++--- .../Implementation/Converters/CieLchuvToCieLuvConverter.cs | 6 +++--- .../Implementation/Converters/CieLuvToCieLchuvConverter.cs | 6 +++--- .../Implementation/Converters/CieLuvToCieXyzConverter.cs | 2 +- .../Implementation/Converters/CieXyzAndCieXyyConverter.cs | 2 +- .../Converters/CieXyzAndHunterLabConverterBase.cs | 2 +- .../Implementation/Converters/CieXyzAndLmsConverter.cs | 2 +- .../Implementation/Converters/CieXyzToCieLabConverter.cs | 2 +- .../Implementation/Converters/CieXyzToCieLuvConverter.cs | 2 +- .../Implementation/Converters/CieXyzToHunterLabConverter.cs | 2 +- .../Implementation/Converters/CieXyzToLinearRgbConverter.cs | 2 +- .../Implementation/Converters/CmykAndRgbConverter.cs | 2 +- .../Implementation/Converters/HslAndRgbConverter.cs | 2 +- .../Implementation/Converters/HsvAndRgbConverter.cs | 4 ++-- .../Implementation/Converters/HunterLabToCieXyzConverter.cs | 6 +++--- .../Converters/LinearRgbAndCieXyzConverterBase.cs | 6 +++--- .../Implementation/Converters/LinearRgbToCieXyzConverter.cs | 6 +++--- .../Implementation/Converters/LinearRgbToRgbConverter.cs | 6 +++--- .../Implementation/Converters/RgbToLinearRgbConverter.cs | 6 +++--- .../Implementation/Converters/YCbCrAndRgbConverter.cs | 2 +- .../Conversion/{ => Implementation}/IChromaticAdaptation.cs | 0 .../Conversion/Implementation/LmsAdaptationMatrix.cs | 6 +++--- .../Implementation/RGBPrimariesChromaticityCoordinates.cs | 4 ++-- .../{ => Implementation}/VonKriesChromaticAdaptation.cs | 5 ++--- .../Implementation/WorkingSpaces/GammaWorkingSpace.cs | 6 +++--- .../Implementation/WorkingSpaces/LWorkingSpace.cs | 6 +++--- .../Implementation/WorkingSpaces/Rec2020WorkingSpace.cs | 6 +++--- .../Implementation/WorkingSpaces/Rec709WorkingSpace.cs | 6 +++--- .../Implementation/WorkingSpaces/RgbWorkingSpace.cs | 6 +++--- .../Implementation/WorkingSpaces/SRgbWorkingSpace.cs | 4 ++-- src/ImageSharp/ColorSpaces/LinearRgb.cs | 6 +++--- src/ImageSharp/ColorSpaces/Rgb.cs | 6 +++--- src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs | 6 +++--- .../Colorspaces/CieXyChromaticityCoordinatesTests.cs | 2 +- .../Colorspaces/Conversion/ApproximateColorspaceComparer.cs | 2 +- .../Conversion/CieLabAndCieLchConversionTests.cs | 4 ++-- .../Conversion/CieLabAndCieLchuvConversionTests.cs | 4 ++-- .../Conversion/CieLabAndCieXyyConversionTests.cs | 4 ++-- .../Colorspaces/Conversion/ColorConverterAdaptTest.cs | 3 +-- .../Colorspaces/StringRepresentationTests.cs | 1 + 59 files changed, 116 insertions(+), 144 deletions(-) rename src/ImageSharp/ColorSpaces/{ => Conversion/Implementation}/CieXyChromaticityCoordinates.cs (97%) rename src/ImageSharp/ColorSpaces/Conversion/{ => Implementation}/IChromaticAdaptation.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/{ => Implementation}/VonKriesChromaticAdaptation.cs (97%) diff --git a/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs index 80b8aee7e7..981e32f8ea 100644 --- a/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -35,4 +35,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding public static float Compress(float channel) => channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F; } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 892c0d5e38..2b9073814f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -1,8 +1,6 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -157,4 +155,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(linearOutput); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 273c9be912..69d0c1bed3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -1,10 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 7f4abfa7bb..52f8724305 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -447,4 +445,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 6ca40af035..2588561c84 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -447,4 +445,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index b790712c50..867b44a784 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index d03c10a01d..344b83254c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -440,4 +438,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 21d576fb41..8362432ab9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -475,4 +473,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.linearRgbToCieXyzConverter = new LinearRgbToCieXyzConverter(workingSpace); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 00e20e25b4..3ff9ac85fd 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -440,4 +438,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 76175f1cba..7c74363919 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -440,4 +438,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index e64beb3e49..e60ad5e20c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -440,4 +438,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index 5b312f4f89..b2c23b5a49 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index fc5665e5c1..e83dcb1258 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -438,4 +436,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.Adapt(rgb); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 68cd34bf2e..4ea1d8d8fb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -1,12 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -407,4 +405,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index bcbd64c77a..05d3b2f2db 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -1,8 +1,7 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { @@ -58,4 +57,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(this.targetRgbWorkingSpace); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs index 65fe799949..27dd989ade 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs @@ -1,8 +1,7 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { @@ -52,4 +51,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix; } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs similarity index 97% rename from src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs index 8e14274f66..1e774fe67a 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs @@ -1,11 +1,11 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; // ReSharper disable CompareOfFloatsByEqualityOperator -namespace SixLabors.ImageSharp.ColorSpaces +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Represents the coordinates of CIEXY chromaticity space. @@ -76,4 +76,4 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieXyChromaticityCoordinates other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs index 40d8c5bc69..014ca1abbd 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs index 2b859205a0..e1bf04aa76 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Converts from to . @@ -38,4 +38,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new CieLch(l, c, hDegrees, input.WhitePoint); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs index dfbbc8f0c7..bafd0df47a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Converts from to . @@ -41,4 +41,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new CieXyz(xyz); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs index ba5b8bfb79..2dae2669fb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Converts from to . @@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new CieLuv(l, u, v, input.WhitePoint); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs index 3c7d356a5e..29fdae69c9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Converts from to . @@ -38,4 +38,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new CieLchuv(l, c, hDegrees, input.WhitePoint); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs index 33f3ec3d3e..09040c98c6 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs index 7767b7b448..f704d1a348 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between CIE XYZ and CIE xyY. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs index 1cd511e819..68f6c495d4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// The base class for converting between and color spaces. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs index f860652b18..a22b097d2b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs @@ -4,7 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between and diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs index c155087ff5..4f4aa84820 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs index 7f2bb0cf6a..96ec96b49c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs index f21235d06c..881d3d9198 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between and diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs index 6497e3060c..25558537a9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs @@ -4,7 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between and diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs index 0700dab43a..8e92ced949 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs @@ -5,7 +5,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between and . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs index 97465e526a..5dbd23b8b8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between HSL and Rgb diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs index 20ada7e7dd..04ab0480b4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between HSV and Rgb @@ -127,4 +127,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new Hsv(h, s, v); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs index 4d6808e6c0..795db7e2c9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between and @@ -36,4 +36,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new CieXyz(x, y, z); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs index bdf451cd3c..1058170758 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs @@ -1,9 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Provides base methods for converting between and color spaces. @@ -74,4 +74,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation }; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs index 21a96071af..adaad50fe0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between and @@ -50,4 +50,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new CieXyz(vector); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs index 8454430935..54081b6393 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs @@ -1,9 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between and . @@ -25,4 +25,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation workingSpace: input.WorkingSpace); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs index 4ddbe42e54..bc8c6f0301 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs @@ -1,9 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between Rgb and LinearRgb. @@ -25,4 +25,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation workingSpace: input.WorkingSpace); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs index ee15ffa508..0821c05c34 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs @@ -5,7 +5,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Color converter between and diff --git a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs index 37e4b1a1a6..8b8e4ab57a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs @@ -1,9 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Matrices used for transformation from to , defining the cone response domain. @@ -131,4 +131,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation M44 = 1F }); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs index 8871d04656..03378f431b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs @@ -1,9 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Represents the chromaticity coordinates of RGB primaries. diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs similarity index 97% rename from src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs index a4d96d19e7..7589a1d570 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs @@ -1,11 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { @@ -99,4 +98,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs index 6caca54cdc..c7020723be 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs @@ -1,11 +1,11 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// The gamma working space. @@ -63,4 +63,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation this.ChromaticityCoordinates, this.Gamma); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs index a2eb42ad0b..d9c4365270 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// L* working space. @@ -29,4 +29,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(InliningOptions.ShortMethod)] public override float Expand(float channel) => LCompanding.Expand(channel); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs index a794b3dda7..4698534db4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. @@ -29,4 +29,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(InliningOptions.ShortMethod)] public override float Expand(float channel) => Rec2020Companding.Expand(channel); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs index ffa9699bc5..80b635cadc 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Rec. 709 (ITU-R Recommendation BT.709) working space. @@ -29,4 +29,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(InliningOptions.ShortMethod)] public override float Expand(float channel) => Rec709Companding.Expand(channel); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs index a97ae22b18..2e5a5a4eb2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs @@ -1,9 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Base class for all implementations of . @@ -81,4 +81,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return HashCode.Combine(this.WhitePoint, this.ChromaticityCoordinates); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs index c3d850251a..c9246f5100 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// The sRgb working space. diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index 7ef50e9c41..c120ef1141 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; +using SixLabors.ImageSharp.ColorSpaces.Conversion; namespace SixLabors.ImageSharp.ColorSpaces { @@ -143,4 +143,4 @@ namespace SixLabors.ImageSharp.ColorSpaces && this.B.Equals(other.B); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index bb71deba3b..3c26b77332 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -1,10 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; +using SixLabors.ImageSharp.ColorSpaces.Conversion; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.ColorSpaces @@ -164,4 +164,4 @@ namespace SixLabors.ImageSharp.ColorSpaces && this.B.Equals(other.B); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs index 3f40fa4f58..152c7ee0bc 100644 --- a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs +++ b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs @@ -1,8 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.ColorSpaces.Companding; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; +using SixLabors.ImageSharp.ColorSpaces.Conversion; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.ColorSpaces @@ -112,4 +112,4 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F))); } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs index 4811a66d45..418893f350 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; namespace SixLabors.ImageSharp.Tests.Colorspaces diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs index feb3b38f0a..2046cdfdc5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; +using SixLabors.ImageSharp.ColorSpaces.Conversion; namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs index 38c0c21bc9..50d831fd90 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -92,4 +92,4 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs index 96628977fe..471610eba0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -80,4 +80,4 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs index f7dc365b81..e007658328 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -76,4 +76,4 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs index 326777f3c6..104b1f4b22 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs @@ -3,7 +3,6 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using Xunit; namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion @@ -178,4 +177,4 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion Assert.Equal(expected, actual, ColorSpaceComparer); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs b/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs index 211b98abb3..df96599945 100644 --- a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs @@ -3,6 +3,7 @@ using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; namespace SixLabors.ImageSharp.Tests.Colorspaces From ce35ce248a4402daa0953c4487c1ff20f1df0117 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 30 Mar 2020 18:42:41 +0200 Subject: [PATCH 088/213] Add additional tga test cases --- .../Formats/Tga/TgaDecoderTests.cs | 85 ++++++++++++++++-- .../Formats/Tga/TgaEncoderTests.cs | 6 +- tests/ImageSharp.Tests/TestImages.cs | 42 ++++++--- tests/Images/External | 2 +- tests/Images/Input/Tga/grayscale_LL.tga | Bin 0 -> 65580 bytes tests/Images/Input/Tga/grayscale_UR.tga | Bin 0 -> 65580 bytes tests/Images/Input/Tga/grayscale_a_UR.tga | Bin 0 -> 131116 bytes tests/Images/Input/Tga/rgb24_top_left.tga | Bin 0 -> 12332 bytes tests/Images/Input/Tga/rgb_a_LL.tga | Bin 0 -> 262188 bytes 9 files changed, 112 insertions(+), 23 deletions(-) create mode 100644 tests/Images/Input/Tga/grayscale_LL.tga create mode 100644 tests/Images/Input/Tga/grayscale_UR.tga create mode 100644 tests/Images/Input/Tga/grayscale_a_UR.tga create mode 100644 tests/Images/Input/Tga/rgb24_top_left.tga create mode 100644 tests/Images/Input/Tga/rgb_a_LL.tga diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index d9f51701e6..ccd00b49f5 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -31,6 +31,42 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Gray8BitBottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Gray_WithBottomLeftOrigin_8Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray8BitTopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Gray_WithTopRightOrigin_8Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Gray8BitBottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Gray_WithBottomRightOrigin_8Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Gray8BitRle, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_8Bit(TestImageProvider provider) @@ -88,6 +124,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Gray16BitTopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Gray_WithTopRightOrigin_16Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + + // Using here the reference output instead of the the reference decoder, + // because the reference decoder output seems not to be correct for 16bit gray images. + image.CompareToReferenceOutput(ImageComparer.Exact, provider); + } + } + [Theory] [WithFile(Gray16BitRle, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_RunLengthEncoded_Gray_16Bit(TestImageProvider provider) @@ -173,8 +224,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } [Theory] - [WithFile(Bit16, PixelTypes.Rgba32)] - public void TgaDecoder_CanDecode_16Bit(TestImageProvider provider) + [WithFile(Bit16BottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WithBottomLeftOrigin_16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(TgaDecoder)) @@ -208,6 +259,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit24BottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WithBottomLeftOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit24TopRight, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_WithTopRightOrigin_24Bit(TestImageProvider provider) @@ -292,6 +355,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit32BottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WithBottomLeftOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit32BottomRight, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_WithBottomRightOrigin_32Bit(TestImageProvider provider) @@ -477,8 +552,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } [Theory] - [WithFile(Bit16, PixelTypes.Rgba32)] - [WithFile(Bit24, PixelTypes.Rgba32)] + [WithFile(Bit16BottomLeft, PixelTypes.Rgba32)] + [WithFile(Bit24BottomLeft, PixelTypes.Rgba32)] [WithFile(Bit32, PixelTypes.Rgba32)] public void TgaDecoder_DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException(TestImageProvider provider) where TPixel : unmanaged, IPixel @@ -489,7 +564,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } [Theory] - [WithFile(Bit24, PixelTypes.Rgba32)] + [WithFile(Bit24BottomLeft, PixelTypes.Rgba32)] [WithFile(Bit32, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_WithLimitedAllocatorBufferCapacity(TestImageProvider provider) where TPixel : unmanaged, IPixel diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs index c6b8b71f99..4e3e2d24c3 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs @@ -26,8 +26,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga new TheoryData { { Gray8Bit, TgaBitsPerPixel.Pixel8 }, - { Bit16, TgaBitsPerPixel.Pixel16 }, - { Bit24, TgaBitsPerPixel.Pixel24 }, + { Bit16BottomLeft, TgaBitsPerPixel.Pixel16 }, + { Bit24BottomLeft, TgaBitsPerPixel.Pixel24 }, { Bit32, TgaBitsPerPixel.Pixel32 }, }; @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga [Theory] [WithFile(Bit32, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel32)] - [WithFile(Bit24, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel24)] + [WithFile(Bit24BottomLeft, PixelTypes.Rgba32, TgaBitsPerPixel.Pixel24)] public void TgaEncoder_WorksWithDiscontiguousBuffers(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel) where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 197210f67a..38ef8d9e2c 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -375,40 +375,54 @@ namespace SixLabors.ImageSharp.Tests public static class Tga { + public const string Gray8Bit = "Tga/targa_8bit.tga"; + public const string Gray8BitBottomLeft = "Tga/grayscale_LL.tga"; + public const string Gray8BitTopRight = "Tga/grayscale_UR.tga"; + public const string Gray8BitBottomRight = "Tga/grayscale_UR.tga"; + public const string Gray8BitRle = "Tga/targa_8bit_rle.tga"; + public const string Bit15 = "Tga/rgb15.tga"; public const string Bit15Rle = "Tga/rgb15rle.tga"; - public const string Bit16 = "Tga/targa_16bit.tga"; + public const string Bit16BottomLeft = "Tga/targa_16bit.tga"; public const string Bit16PalRle = "Tga/ccm8.tga"; - public const string Bit24 = "Tga/targa_24bit.tga"; - public const string Bit24TopRight = "Tga/rgb_UR.tga"; + + public const string Gray16Bit = "Tga/grayscale_a_UL.tga"; + public const string Gray16BitBottomLeft = "Tga/grayscale_a_LL.tga"; + public const string Gray16BitBottomRight = "Tga/grayscale_a_LR.tga"; + public const string Gray16BitTopRight = "Tga/grayscale_a_UR.tga"; + public const string Gray16BitRle = "Tga/grayscale_a_rle_UL.tga"; + public const string Gray16BitRleBottomLeft = "Tga/grayscale_a_rle_LL.tga"; + public const string Gray16BitRleBottomRight = "Tga/grayscale_a_rle_LR.tga"; + public const string Gray16BitRleTopRight = "Tga/grayscale_a_rle_UR.tga"; + + public const string Bit24 = "Tga/rgb24_top_left.tga"; + public const string Bit24BottomLeft = "Tga/targa_24bit.tga"; public const string Bit24BottomRight = "Tga/rgb_LR.tga"; + public const string Bit24TopRight = "Tga/rgb_UR.tga"; public const string Bit24TopLeft = "Tga/targa_24bit_pal_origin_topleft.tga"; + public const string Bit24RleTopLeft = "Tga/targa_24bit_rle_origin_topleft.tga"; public const string Bit24RleTopRight = "Tga/rgb_rle_UR.tga"; public const string Bit24RleBottomRight = "Tga/rgb_rle_LR.tga"; + public const string Bit32 = "Tga/targa_32bit.tga"; + public const string Bit32BottomLeft = "Tga/rgb_a_LL.tga"; + public const string Bit32TopRight = "Tga/rgb_a_UR.tga"; + public const string Bit32BottomRight = "Tga/rgb_a_LR.tga"; + public const string Bit32Pal = "Tga/indexed_a_UL.tga"; public const string Bit32PalBottomLeft = "Tga/indexed_a_LL.tga"; public const string Bit32PalBottomRight = "Tga/indexed_a_LR.tga"; public const string Bit32PalTopRight = "Tga/indexed_a_UR.tga"; - public const string Bit32TopRight = "Tga/rgb_a_UR.tga"; - public const string Bit32BottomRight = "Tga/rgb_a_LR.tga"; public const string Bit32RleTopRight = "Tga/rgb_a_rle_UR.tga"; public const string Bit32RleBottomRight = "Tga/rgb_a_rle_LR.tga"; - public const string Gray8Bit = "Tga/targa_8bit.tga"; - public const string Gray8BitRle = "Tga/targa_8bit_rle.tga"; - public const string Gray16Bit = "Tga/grayscale_a_UL.tga"; - public const string Gray16BitBottomLeft = "Tga/grayscale_a_LL.tga"; - public const string Gray16BitBottomRight = "Tga/grayscale_a_LR.tga"; - public const string Gray16BitRle = "Tga/grayscale_a_rle_UL.tga"; - public const string Gray16BitRleBottomLeft = "Tga/grayscale_a_rle_LL.tga"; - public const string Gray16BitRleBottomRight = "Tga/grayscale_a_rle_LR.tga"; - public const string Gray16BitRleTopRight = "Tga/grayscale_a_rle_UR.tga"; + public const string Bit16Rle = "Tga/targa_16bit_rle.tga"; public const string Bit24Rle = "Tga/targa_24bit_rle.tga"; public const string Bit32Rle = "Tga/targa_32bit_rle.tga"; public const string Bit16Pal = "Tga/targa_16bit_pal.tga"; public const string Bit24Pal = "Tga/targa_24bit_pal.tga"; + public const string NoAlphaBits16Bit = "Tga/16bit_noalphabits.tga"; public const string NoAlphaBits16BitRle = "Tga/16bit_rle_noalphabits.tga"; public const string NoAlphaBits32Bit = "Tga/32bit_no_alphabits.tga"; diff --git a/tests/Images/External b/tests/Images/External index 6f81d7a95e..fe694a3938 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 6f81d7a95e285b1449efd4319a5cc7b071dec679 +Subproject commit fe694a3938bea3565071a96cb1c90c4cbc586ff9 diff --git a/tests/Images/Input/Tga/grayscale_LL.tga b/tests/Images/Input/Tga/grayscale_LL.tga new file mode 100644 index 0000000000000000000000000000000000000000..fe9ba822fb49775dd3fa67335b6495447f568c3f GIT binary patch literal 65580 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 bU;T;a{n+#V*5CY|zxUkd{per)-qQaCj7ZG& literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/grayscale_UR.tga b/tests/Images/Input/Tga/grayscale_UR.tga new file mode 100644 index 0000000000000000000000000000000000000000..dc09c5f38c44217cc9f2a51bb7f383a604efa8ae GIT binary patch literal 65580 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 QZ?w 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 M#(npH{c|n<2S{G1i2wiq literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/rgb24_top_left.tga b/tests/Images/Input/Tga/rgb24_top_left.tga new file mode 100644 index 0000000000000000000000000000000000000000..2ad891c2875d83999702f64be225c84b7ed9e680 GIT binary patch literal 12332 zcmeI3J#GRq5Js(tGSsBZ1(JpfY_pM&P$K0|xeT<3k^<3j20A(_jsOiOphOfD9`m8O+W6${cf!GSA?vxoxlBh&IJQ4;BzyJ)u01UtY48Q;kzyJ(HF`({= zpC}Fgxe3GT;1&n?%l*_!^}k%wXhhTLUcq8Poem8KwA*EjC{p5MH~IWQoM}_Yq}`@U zW&cbjRIS>0K0l!SL2j;d*yR2G1pInh@MyIxbFF3reV5tnfOb89!B=2@jh&`69#g+h zn~lJ)Q~tNec|CR>WZc&H5%bsUwB3gN8JHK2Gw$W(tM;$J#RUY+-|Gq8nN|mSIhfi4 z5mihICtRD#&+o&V>)bAX#+s;FOlHdBOiuU@gqx{ws*kE;GyJ4b6D@TqKVQlb_^4v+ zw#JW6@aw~vRtzkS$m}QMQ@f7cu6=C{hc0O%k=ak$0w47_4!g#muU52P3vC6|>?h)C z47Qo`72I+;(FOeF0G>J3=NIEM^<^)M%$zKnF7Npa%t78t?1KRqfB_hQ0T_S*7=Qs7 ofB_hQ0T_S*7=Qs7xCI0D?*Qua{VV-$d^Fx(pMG8%&GcFQ0wl*ysQ>@~ literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/rgb_a_LL.tga b/tests/Images/Input/Tga/rgb_a_LL.tga new file mode 100644 index 0000000000000000000000000000000000000000..746bc9e006d7c41977cb5078265b3245f41cc2e6 GIT binary patch literal 262188 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

/// The image this method extends. - /// The pixel format. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source) - where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor()); + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source) + => source.ApplyProcessor(new AdaptiveThresholdProcessor()); /// /// Applies Bradley Adaptive Threshold to the image. /// /// The image this method extends. /// Threshold limit (0.0-1.0) to consider for binarization. - /// The pixel format. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, float thresholdLimit) - where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor(thresholdLimit)); + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, float thresholdLimit) + => source.ApplyProcessor(new AdaptiveThresholdProcessor(thresholdLimit)); /// /// Applies Bradley Adaptive Threshold to the image. /// /// The image this method extends. /// Upper (white) color for thresholding. - /// Lower (black) color for thresholding - /// The pixel format. + /// Lower (black) color for thresholding. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower) - where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower)); + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower) + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower)); /// /// Applies Bradley Adaptive Threshold to the image. /// /// The image this method extends. /// Upper (white) color for thresholding. - /// Lower (black) color for thresholding + /// Lower (black) color for thresholding. /// Threshold limit (0.0-1.0) to consider for binarization. - /// The pixel format. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, float thresholdLimit) - where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, thresholdLimit)); + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower, float thresholdLimit) + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, thresholdLimit)); /// /// The image this method extends. /// Upper (white) color for thresholding. - /// Lower (black) color for thresholding + /// Lower (black) color for thresholding. /// Threshold limit (0.0-1.0) to consider for binarization. /// Rectangle region to apply the processor on. /// The . From 5754f9493fdebdf9cb32dc3f54bd57a14c9a227c Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 5 Apr 2020 13:30:01 +0200 Subject: [PATCH 102/213] For paletted Bgra5551 alpha bits are not ignored --- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 27 ++++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 7753b916d3..816a472fb2 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -252,14 +252,14 @@ namespace SixLabors.ImageSharp.Formats.Tga { for (int x = width - 1; x >= 0; x--) { - this.ReadPalettedBgr16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow); + this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow); } } else { for (int x = 0; x < width; x++) { - this.ReadPalettedBgr16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow); + this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow); } } @@ -338,11 +338,7 @@ namespace SixLabors.ImageSharp.Formats.Tga color.FromL8(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 2: - Bgra5551 bgra = Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]); - - // Set alpha value to 1, to treat it as opaque for Bgra5551. - bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); - color.FromBgra5551(bgra); + this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes, ref color); break; case 3: color.FromBgr24(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); @@ -723,20 +719,29 @@ namespace SixLabors.ImageSharp.Formats.Tga PixelOperations.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width); } - private void ReadPalettedBgr16Pixel(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReadPalettedBgra16Pixel(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = this.currentStream.ReadByte(); + this.ReadPalettedBgra16Pixel(palette, colorIndex, colorMapPixelSizeInBytes, ref color); + pixelRow[x] = color; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReadPalettedBgra16Pixel(byte[] palette, int index, int colorMapPixelSizeInBytes, ref TPixel color) + where TPixel : unmanaged, IPixel + { Bgra5551 bgra = default; - bgra.FromBgra5551(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); + bgra.FromBgra5551(Unsafe.As(ref palette[index * colorMapPixelSizeInBytes])); + if (!this.hasAlpha) { - // Set alpha value to 1, to treat it as opaque for Bgra5551. + // Set alpha value to 1, to treat it as opaque. bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); } color.FromBgra5551(bgra); - pixelRow[x] = color; } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 88f3bd0c33d1448a5c9cfe6b66bd60e1a2b4672c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 6 Apr 2020 20:51:45 +0100 Subject: [PATCH 103/213] Minor performance improvements. --- Directory.Build.targets | 6 ++-- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 7 ++++- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 29 +++++++++++++------ .../Formats/Png/Zlib/DeflaterEngine.cs | 16 ++++++---- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index e5c44f7761..83322cabfe 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -23,12 +23,12 @@ - + - - + + diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 4d7de4161b..bc7b9d8150 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -380,7 +380,12 @@ namespace SixLabors.ImageSharp.Formats.Png private void InitializeImage(ImageMetadata metadata, out Image image) where TPixel : unmanaged, IPixel { - image = new Image(this.configuration, this.header.Width, this.header.Height, metadata); + image = Image.CreateUninitialized( + this.configuration, + this.header.Width, + this.header.Height, + metadata); + this.bytesPerPixel = this.CalculateBytesPerPixel(); this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1; this.bytesPerSample = 1; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 45e1ffd2d7..fcbbc66974 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -5,10 +5,8 @@ using System; using System.Buffers; using System.Buffers.Binary; using System.IO; -using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; @@ -16,7 +14,6 @@ using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Formats.Png { @@ -633,10 +630,21 @@ namespace SixLabors.ImageSharp.Formats.Png private void WriteTextChunks(Stream stream, PngMetadata meta) { const int MaxLatinCode = 255; - foreach (PngTextData textData in meta.TextData) + for (int i = 0; i < meta.TextData.Count; i++) { - bool hasUnicodeCharacters = textData.Value.Any(c => c > MaxLatinCode); - if (hasUnicodeCharacters || (!string.IsNullOrWhiteSpace(textData.LanguageTag) || !string.IsNullOrWhiteSpace(textData.TranslatedKeyword))) + PngTextData textData = meta.TextData[i]; + bool hasUnicodeCharacters = false; + foreach (var c in textData.Value) + { + if (c > MaxLatinCode) + { + hasUnicodeCharacters = true; + break; + } + } + + if (hasUnicodeCharacters || (!string.IsNullOrWhiteSpace(textData.LanguageTag) || + !string.IsNullOrWhiteSpace(textData.TranslatedKeyword))) { // Write iTXt chunk. byte[] keywordBytes = PngConstants.Encoding.GetBytes(textData.Keyword); @@ -647,7 +655,8 @@ namespace SixLabors.ImageSharp.Formats.Png byte[] translatedKeyword = PngConstants.TranslatedEncoding.GetBytes(textData.TranslatedKeyword); byte[] languageTag = PngConstants.LanguageEncoding.GetBytes(textData.LanguageTag); - Span outputBytes = new byte[keywordBytes.Length + textBytes.Length + translatedKeyword.Length + languageTag.Length + 5]; + Span outputBytes = new byte[keywordBytes.Length + textBytes.Length + + translatedKeyword.Length + languageTag.Length + 5]; keywordBytes.CopyTo(outputBytes); if (textData.Value.Length > this.options.TextCompressionThreshold) { @@ -667,7 +676,8 @@ namespace SixLabors.ImageSharp.Formats.Png if (textData.Value.Length > this.options.TextCompressionThreshold) { // Write zTXt chunk. - byte[] compressedData = this.GetCompressedTextBytes(PngConstants.Encoding.GetBytes(textData.Value)); + byte[] compressedData = + this.GetCompressedTextBytes(PngConstants.Encoding.GetBytes(textData.Value)); Span outputBytes = new byte[textData.Keyword.Length + compressedData.Length + 2]; PngConstants.Encoding.GetBytes(textData.Keyword).CopyTo(outputBytes); compressedData.CopyTo(outputBytes.Slice(textData.Keyword.Length + 2)); @@ -678,7 +688,8 @@ namespace SixLabors.ImageSharp.Formats.Png // Write tEXt chunk. Span outputBytes = new byte[textData.Keyword.Length + textData.Value.Length + 1]; PngConstants.Encoding.GetBytes(textData.Keyword).CopyTo(outputBytes); - PngConstants.Encoding.GetBytes(textData.Value).CopyTo(outputBytes.Slice(textData.Keyword.Length + 1)); + PngConstants.Encoding.GetBytes(textData.Value) + .CopyTo(outputBytes.Slice(textData.Keyword.Length + 1)); this.WriteChunk(stream, PngChunkType.Text, outputBytes.ToArray()); } } diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs index c1c86a98be..0410a74613 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs @@ -525,12 +525,15 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib break; case 2: - if (pinnedWindow[++scan] == pinnedWindow[++match] - && pinnedWindow[++scan] == pinnedWindow[++match]) + if ((short*)pinnedWindow[++scan] == (short*)pinnedWindow[++match]) { + ++scan; + ++match; break; } + ++scan; + ++match; break; case 3: @@ -544,14 +547,15 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib break; case 4: - if (pinnedWindow[++scan] == pinnedWindow[++match] - && pinnedWindow[++scan] == pinnedWindow[++match] - && pinnedWindow[++scan] == pinnedWindow[++match] - && pinnedWindow[++scan] == pinnedWindow[++match]) + if ((int*)pinnedWindow[++scan] == (int*)pinnedWindow[++match]) { + scan += 3; + match += 3; break; } + scan += 3; + match += 3; break; case 5: From 29d12f3f005ea05fb9d40c7e5c3eb4d14b739d78 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 6 Apr 2020 21:30:22 +0100 Subject: [PATCH 104/213] Revert bad optimization --- .../Formats/Png/Zlib/DeflaterEngine.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs index 0410a74613..c1c86a98be 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs @@ -525,15 +525,12 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib break; case 2: - if ((short*)pinnedWindow[++scan] == (short*)pinnedWindow[++match]) + if (pinnedWindow[++scan] == pinnedWindow[++match] + && pinnedWindow[++scan] == pinnedWindow[++match]) { - ++scan; - ++match; break; } - ++scan; - ++match; break; case 3: @@ -547,15 +544,14 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib break; case 4: - if ((int*)pinnedWindow[++scan] == (int*)pinnedWindow[++match]) + if (pinnedWindow[++scan] == pinnedWindow[++match] + && pinnedWindow[++scan] == pinnedWindow[++match] + && pinnedWindow[++scan] == pinnedWindow[++match] + && pinnedWindow[++scan] == pinnedWindow[++match]) { - scan += 3; - match += 3; break; } - scan += 3; - match += 3; break; case 5: From 6dae630dc4601f84e321fefc471f6fb2168ffcea Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 8 Apr 2020 20:47:46 +0100 Subject: [PATCH 105/213] Predefine Codes and Lengths, use ReadOnlySpan where possible. --- .../Formats/Png/Zlib/DeflaterHuffman.cs | 117 ++++++++++-------- 1 file changed, 67 insertions(+), 50 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs index 8380f7d5b9..161760602e 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs @@ -36,11 +36,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib private const int EofSymbol = 256; - private static readonly short[] StaticLCodes; - private static readonly byte[] StaticLLength; - private static readonly short[] StaticDCodes; - private static readonly byte[] StaticDLength; - private Tree literalTree; private Tree distTree; private Tree blTree; @@ -58,49 +53,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib private int extraBits; private bool isDisposed; - // TODO: These should be pre-generated array/readonlyspans. - static DeflaterHuffman() - { - // See RFC 1951 3.2.6 - // Literal codes - StaticLCodes = new short[LiteralNumber]; - StaticLLength = new byte[LiteralNumber]; - - int i = 0; - while (i < 144) - { - StaticLCodes[i] = BitReverse((0x030 + i) << 8); - StaticLLength[i++] = 8; - } - - while (i < 256) - { - StaticLCodes[i] = BitReverse((0x190 - 144 + i) << 7); - StaticLLength[i++] = 9; - } - - while (i < 280) - { - StaticLCodes[i] = BitReverse((0x000 - 256 + i) << 9); - StaticLLength[i++] = 7; - } - - while (i < LiteralNumber) - { - StaticLCodes[i] = BitReverse((0x0c0 - 280 + i) << 8); - StaticLLength[i++] = 8; - } - - // Distance codes - StaticDCodes = new short[DistanceNumber]; - StaticDLength = new byte[DistanceNumber]; - for (i = 0; i < DistanceNumber; i++) - { - StaticDCodes[i] = BitReverse(i << 11); - StaticDLength[i] = 5; - } - } - /// /// Initializes a new instance of the class. /// @@ -122,12 +74,77 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib this.pinnedLiteralBuffer = (short*)this.literalBufferHandle.Pointer; } + // See RFC 1951 3.2.6 + // Literal codes + private static short[] StaticLCodes => new short[] + { + 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, + 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, + 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, + 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, + 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, + 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 19, + 275, 147, 403, 83, 339, 211, 467, 51, 307, 179, 435, 115, 371, 243, 499, + 11, 267, 139, 395, 75, 331, 203, 459, 43, 299, 171, 427, 107, 363, 235, 491, + 27, 283, 155, 411, 91, 347, 219, 475, 59, 315, 187, 443, 123, 379, 251, 507, + 7, 263, 135, 391, 71, 327, 199, 455, 39, 295, 167, 423, 103, 359, 231, 487, + 23, 279, 151, 407, 87, 343, 215, 471, 55, 311, 183, 439, 119, 375, 247, 503, + 15, 271, 143, 399, 79, 335, 207, 463, 47, 303, 175, 431, 111, 367, 239, 495, + 31, 287, 159, 415, 95, 351, 223, 479, 63, 319, 191, 447, 127, 383, 255, 511, + 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, 4, 68, 36, + 100, 20, 84, 52, 116, 3, 131, 67, 195, 35, 163 + }; + + private static ReadOnlySpan StaticLLength => new byte[] + { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8 + }; + + // Distance codes and lengths. + private static short[] StaticDCodes => new short[] + { + 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, + 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23 + }; + + private static ReadOnlySpan StaticDLength => new byte[] + { + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + }; + /// /// Gets the lengths of the bit length codes are sent in order of decreasing probability, to avoid transmitting the lengths for unused bit length codes. /// - private static ReadOnlySpan BitLengthOrder => new byte[] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + private static ReadOnlySpan BitLengthOrder => new byte[] + { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; - private static ReadOnlySpan Bit4Reverse => new byte[] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; + private static ReadOnlySpan Bit4Reverse => new byte[] + { + 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 + }; /// /// Gets the pending buffer to use. From 43b77b9036b44e24f9b9f90c09810a02ae9faa10 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 8 Apr 2020 22:51:32 +0100 Subject: [PATCH 106/213] Use static fields. See if dll version fix CI 472 build --- Directory.Build.targets | 6 +++--- src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 83322cabfe..e5c44f7761 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -23,12 +23,12 @@ - + - - + + diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs index 161760602e..022d3d4d0d 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs @@ -74,9 +74,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib this.pinnedLiteralBuffer = (short*)this.literalBufferHandle.Pointer; } +#pragma warning disable SA1201 // Elements should appear in the correct order + // See RFC 1951 3.2.6 // Literal codes - private static short[] StaticLCodes => new short[] + private static readonly short[] StaticLCodes = new short[] { 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, @@ -121,7 +123,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib }; // Distance codes and lengths. - private static short[] StaticDCodes => new short[] + private static readonly short[] StaticDCodes = new short[] { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23 @@ -132,6 +134,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; +#pragma warning restore SA1201 // Elements should appear in the correct order /// /// Gets the lengths of the bit length codes are sent in order of decreasing probability, to avoid transmitting the lengths for unused bit length codes. From 026698ac4832a3f26af1d2f492d8b5963774ad5c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 9 Apr 2020 21:10:26 +0100 Subject: [PATCH 107/213] Fix #1166 --- Directory.Build.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index e5c44f7761..0f02d7e320 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -18,7 +18,7 @@ - + From 28f3938de2c5845d88e05d516a216a0dd04baad9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 9 Apr 2020 23:45:23 +0100 Subject: [PATCH 108/213] Improve accessability of Span methods. Fixes #1164 --- .../Advanced/AdvancedImageExtensions.cs | 78 ------------------- src/ImageSharp/ImageFrame{TPixel}.cs | 34 ++++++++ src/ImageSharp/Image{TPixel}.cs | 33 ++++++++ .../Advanced/AdvancedImageExtensionsTests.cs | 5 +- .../Drawing/DrawImageTests.cs | 3 +- .../Formats/Gif/GifDecoderTests.cs | 5 +- .../Formats/Tga/TgaTestUtils.cs | 4 +- .../ImageFrameCollectionTests.Generic.cs | 22 ++++-- .../ImageFrameCollectionTests.NonGeneric.cs | 6 +- .../Image/ImageTests.WrapMemory.cs | 10 ++- tests/ImageSharp.Tests/Image/ImageTests.cs | 9 ++- .../Transforms/AffineTransformTests.cs | 2 +- .../Processors/Transforms/ResizeTests.cs | 3 +- .../TestUtilities/TestImageExtensions.cs | 11 +-- .../TestUtilities/TestUtils.cs | 6 +- 15 files changed, 122 insertions(+), 109 deletions(-) diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 0273f02f56..a79733fec3 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -78,84 +78,6 @@ namespace SixLabors.ImageSharp.Advanced where TPixel : unmanaged, IPixel => source?.Frames.RootFrame.GetPixelMemoryGroup() ?? throw new ArgumentNullException(nameof(source)); - /// - /// Gets the representation of the pixels as a in the source image's pixel format - /// stored in row major order, if the backing buffer is contiguous. - /// - /// The type of the pixel. - /// The source image. - /// The - /// Thrown when the backing buffer is discontiguous. - [Obsolete( - @"GetPixelSpan might fail, because the backing buffer could be discontiguous for large images. Use GetPixelMemoryGroup or GetPixelRowSpan instead!")] - public static Span GetPixelSpan(this ImageFrame source) - where TPixel : unmanaged, IPixel - { - Guard.NotNull(source, nameof(source)); - - IMemoryGroup mg = source.GetPixelMemoryGroup(); - if (mg.Count > 1) - { - throw new InvalidOperationException($"GetPixelSpan is invalid, since the backing buffer of this {source.Width}x{source.Height} sized image is discontiguous!"); - } - - return mg.Single().Span; - } - - /// - /// Gets the representation of the pixels as a of contiguous memory in the source image's pixel format - /// stored in row major order. - /// - /// The type of the pixel. - /// The source. - /// The - /// Thrown when the backing buffer is discontiguous. - [Obsolete( - @"GetPixelSpan might fail, because the backing buffer could be discontiguous for large images. Use GetPixelMemoryGroup or GetPixelRowSpan instead!")] - public static Span GetPixelSpan(this Image source) - where TPixel : unmanaged, IPixel - { - Guard.NotNull(source, nameof(source)); - - return source.Frames.RootFrame.GetPixelSpan(); - } - - /// - /// Gets the representation of the pixels as a of contiguous memory - /// at row beginning from the the first pixel on that row. - /// - /// The type of the pixel. - /// The source. - /// The row. - /// The - public static Span GetPixelRowSpan(this ImageFrame source, int rowIndex) - where TPixel : unmanaged, IPixel - { - Guard.NotNull(source, nameof(source)); - Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); - Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex)); - - return source.PixelBuffer.GetRowSpan(rowIndex); - } - - /// - /// Gets the representation of the pixels as of of contiguous memory - /// at row beginning from the the first pixel on that row. - /// - /// The type of the pixel. - /// The source. - /// The row. - /// The - public static Span GetPixelRowSpan(this Image source, int rowIndex) - where TPixel : unmanaged, IPixel - { - Guard.NotNull(source, nameof(source)); - Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); - Guard.MustBeLessThan(rowIndex, source.Height, nameof(rowIndex)); - - return source.Frames.RootFrame.PixelBuffer.GetRowSpan(rowIndex); - } - /// /// Gets the representation of the pixels as a of contiguous memory /// at row beginning from the the first pixel on that row. diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index a35443ec9d..0c00349f2b 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; @@ -166,6 +167,39 @@ namespace SixLabors.ImageSharp } } + /// + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the first pixel on that row. + /// + /// The row. + /// The + public Span GetPixelRowSpan(int rowIndex) + { + Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); + Guard.MustBeLessThan(rowIndex, this.Height, nameof(rowIndex)); + + return this.PixelBuffer.GetRowSpan(rowIndex); + } + + /// + /// Gets the representation of the pixels as a in the source image's pixel format + /// stored in row major order, if the backing buffer is contiguous. + /// + /// The . + /// The . + public bool TryGetSinglePixelSpan(out Span span) + { + IMemoryGroup mg = this.GetPixelMemoryGroup(); + if (mg.Count > 1) + { + span = default; + return false; + } + + span = mg.Single().Span; + return true; + } + /// /// Gets a reference to the pixel at the specified position. /// diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 56f1f6b7bf..20be772e2e 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -163,6 +163,39 @@ namespace SixLabors.ImageSharp } } + /// + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the first pixel on that row. + /// + /// The row. + /// The + public Span GetPixelRowSpan(int rowIndex) + { + Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); + Guard.MustBeLessThan(rowIndex, this.Height, nameof(rowIndex)); + + return this.PixelSource.PixelBuffer.GetRowSpan(rowIndex); + } + + /// + /// Gets the representation of the pixels as a in the source image's pixel format + /// stored in row major order, if the backing buffer is contiguous. + /// + /// The . + /// The . + public bool TryGetSinglePixelSpan(out Span span) + { + IMemoryGroup mg = this.GetPixelMemoryGroup(); + if (mg.Count > 1) + { + span = default; + return false; + } + + span = mg.Single().Span; + return true; + } + /// /// Clones the current image /// diff --git a/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs b/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs index dca124849a..97731be94e 100644 --- a/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs @@ -61,7 +61,10 @@ namespace SixLabors.ImageSharp.Tests.Advanced { using Image image0 = provider.GetImage(); var targetBuffer = new TPixel[image0.Width * image0.Height]; - image0.GetPixelSpan().CopyTo(targetBuffer); + + Assert.True(image0.TryGetSinglePixelSpan(out Span sourceBuffer)); + + sourceBuffer.CopyTo(targetBuffer); var managerOfExternalMemory = new TestMemoryManager(targetBuffer); diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs index c3bc2f2ae2..d08d81899b 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs @@ -128,7 +128,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing using (Image background = provider.GetImage()) using (var overlay = new Image(50, 50)) { - overlay.GetPixelSpan().Fill(Color.Black); + Assert.True(overlay.TryGetSinglePixelSpan(out Span overlaySpan)); + overlaySpan.Fill(Color.Black); background.Mutate(c => c.DrawImage(overlay, new Point(x, y), PixelColorBlendingMode.Normal, 1F)); diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index fa28993720..b3a99aa1c0 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -164,7 +164,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif { ImageFrame first = kumin1.Frames[i]; ImageFrame second = kumin2.Frames[i]; - first.ComparePixelBufferTo(second.GetPixelSpan()); + + Assert.True(second.TryGetSinglePixelSpan(out Span secondSpan)); + + first.ComparePixelBufferTo(secondSpan); } } } diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs index c69cf2f20b..48171a77dc 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs @@ -9,6 +9,7 @@ using ImageMagick; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Tga { @@ -46,7 +47,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga { magickImage.AutoOrient(); var result = new Image(configuration, magickImage.Width, magickImage.Height); - Span resultPixels = result.GetPixelSpan(); + + Assert.True(result.TryGetSinglePixelSpan(out Span resultPixels)); using (IPixelCollection pixels = magickImage.GetPixelsUnsafe()) { diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs index 9ea6a305c3..2b7c1e2c60 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs @@ -198,7 +198,9 @@ namespace SixLabors.ImageSharp.Tests using (Image cloned = img.Frames.CloneFrame(0)) { Assert.Equal(2, img.Frames.Count); - cloned.ComparePixelBufferTo(img.GetPixelSpan()); + Assert.True(img.TryGetSinglePixelSpan(out Span imgSpan)); + + cloned.ComparePixelBufferTo(imgSpan); } } } @@ -210,7 +212,8 @@ namespace SixLabors.ImageSharp.Tests { using (Image img = provider.GetImage()) { - var sourcePixelData = img.GetPixelSpan().ToArray(); + Assert.True(img.TryGetSinglePixelSpan(out Span imgSpan)); + TPixel[] sourcePixelData = imgSpan.ToArray(); img.Frames.AddFrame(new ImageFrame(Configuration.Default, 10, 10)); using (Image cloned = img.Frames.ExportFrame(0)) @@ -242,7 +245,8 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void AddFrameFromPixelData() { - var pixelData = this.Image.Frames.RootFrame.GetPixelSpan().ToArray(); + Assert.True(this.Image.Frames.RootFrame.TryGetSinglePixelSpan(out Span imgSpan)); + var pixelData = imgSpan.ToArray(); this.Image.Frames.AddFrame(pixelData); Assert.Equal(2, this.Image.Frames.Count); } @@ -251,8 +255,10 @@ namespace SixLabors.ImageSharp.Tests public void AddFrame_clones_sourceFrame() { var otherFrame = new ImageFrame(Configuration.Default, 10, 10); - var addedFrame = this.Image.Frames.AddFrame(otherFrame); - addedFrame.ComparePixelBufferTo(otherFrame.GetPixelSpan()); + ImageFrame addedFrame = this.Image.Frames.AddFrame(otherFrame); + + Assert.True(otherFrame.TryGetSinglePixelSpan(out Span otherFrameSpan)); + addedFrame.ComparePixelBufferTo(otherFrameSpan); Assert.NotEqual(otherFrame, addedFrame); } @@ -260,8 +266,10 @@ namespace SixLabors.ImageSharp.Tests public void InsertFrame_clones_sourceFrame() { var otherFrame = new ImageFrame(Configuration.Default, 10, 10); - var addedFrame = this.Image.Frames.InsertFrame(0, otherFrame); - addedFrame.ComparePixelBufferTo(otherFrame.GetPixelSpan()); + ImageFrame addedFrame = this.Image.Frames.InsertFrame(0, otherFrame); + + Assert.True(otherFrame.TryGetSinglePixelSpan(out Span otherFrameSpan)); + addedFrame.ComparePixelBufferTo(otherFrameSpan); Assert.NotEqual(otherFrame, addedFrame); } diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs index 08e6f8e1f0..a05b428e15 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs @@ -159,7 +159,8 @@ namespace SixLabors.ImageSharp.Tests var expectedClone = (Image)cloned; - expectedClone.ComparePixelBufferTo(img.GetPixelSpan()); + Assert.True(img.TryGetSinglePixelSpan(out Span imgSpan)); + expectedClone.ComparePixelBufferTo(imgSpan); } } } @@ -171,7 +172,8 @@ namespace SixLabors.ImageSharp.Tests { using (Image img = provider.GetImage()) { - var sourcePixelData = img.GetPixelSpan().ToArray(); + Assert.True(img.TryGetSinglePixelSpan(out Span imgSpan)); + var sourcePixelData = imgSpan.ToArray(); ImageFrameCollection nonGenericFrameCollection = img.Frames; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 423309dfb8..e0152558b5 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -91,7 +91,8 @@ namespace SixLabors.ImageSharp.Tests using (var image = Image.WrapMemory(cfg, memory, 5, 5, metaData)) { - ref Rgba32 pixel0 = ref image.GetPixelSpan()[0]; + Assert.True(image.TryGetSinglePixelSpan(out Span imageSpan)); + ref Rgba32 pixel0 = ref imageSpan[0]; Assert.True(Unsafe.AreSame(ref array[0], ref pixel0)); Assert.Equal(cfg, image.GetConfiguration()); @@ -118,7 +119,8 @@ namespace SixLabors.ImageSharp.Tests using (var image = Image.WrapMemory(memory, bmp.Width, bmp.Height)) { Assert.Equal(memory, image.GetRootFramePixelBuffer().GetSingleMemory()); - image.GetPixelSpan().Fill(bg); + Assert.True(image.TryGetSinglePixelSpan(out Span imageSpan)); + imageSpan.Fill(bg); for (var i = 10; i < 20; i++) { image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg); @@ -153,8 +155,8 @@ namespace SixLabors.ImageSharp.Tests using (var image = Image.WrapMemory(memoryManager, bmp.Width, bmp.Height)) { Assert.Equal(memoryManager.Memory, image.GetRootFramePixelBuffer().GetSingleMemory()); - - image.GetPixelSpan().Fill(bg); + Assert.True(image.TryGetSinglePixelSpan(out Span imageSpan)); + imageSpan.Fill(bg); for (var i = 10; i < 20; i++) { image.GetPixelRowSpan(i).Slice(10, 10).Fill(fg); diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index c99b75733a..6bba8b15c7 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -27,7 +27,8 @@ namespace SixLabors.ImageSharp.Tests { Assert.Equal(11, image.Width); Assert.Equal(23, image.Height); - Assert.Equal(11 * 23, image.GetPixelSpan().Length); + Assert.True(image.TryGetSinglePixelSpan(out Span imageSpan)); + Assert.Equal(11 * 23, imageSpan.Length); image.ComparePixelBufferTo(default(Rgba32)); Assert.Equal(Configuration.Default, image.GetConfiguration()); @@ -43,7 +44,8 @@ namespace SixLabors.ImageSharp.Tests { Assert.Equal(11, image.Width); Assert.Equal(23, image.Height); - Assert.Equal(11 * 23, image.GetPixelSpan().Length); + Assert.True(image.TryGetSinglePixelSpan(out Span imageSpan)); + Assert.Equal(11 * 23, imageSpan.Length); image.ComparePixelBufferTo(default(Rgba32)); Assert.Equal(configuration, image.GetConfiguration()); @@ -60,7 +62,8 @@ namespace SixLabors.ImageSharp.Tests { Assert.Equal(11, image.Width); Assert.Equal(23, image.Height); - Assert.Equal(11 * 23, image.GetPixelSpan().Length); + Assert.True(image.TryGetSinglePixelSpan(out Span imageSpan)); + Assert.Equal(11 * 23, imageSpan.Length); image.ComparePixelBufferTo(color); Assert.Equal(configuration, image.GetConfiguration()); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs index cdc77d3216..2de903d664 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs @@ -241,7 +241,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms private static void VerifyAllPixelsAreWhiteOrTransparent(Image image) where TPixel : unmanaged, IPixel { - Span data = image.Frames.RootFrame.GetPixelSpan(); + Assert.True(image.Frames.RootFrame.TryGetSinglePixelSpan(out Span data)); var white = new Rgb24(255, 255, 255); foreach (TPixel pixel in data) { diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 655bcfea4b..3f323000ab 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -244,7 +244,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { using (Image image0 = provider.GetImage()) { - var mmg = TestMemoryManager.CreateAsCopyOf(image0.GetPixelSpan()); + Assert.True(image0.TryGetSinglePixelSpan(out Span imageSpan)); + var mmg = TestMemoryManager.CreateAsCopyOf(imageSpan); using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 8ecb2ee6ce..fbdb512dea 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -417,8 +417,7 @@ namespace SixLabors.ImageSharp.Tests Span expectedPixels) where TPixel : unmanaged, IPixel { - Span actualPixels = image.GetPixelSpan(); - + Assert.True(image.TryGetSinglePixelSpan(out Span actualPixels)); CompareBuffers(expectedPixels, actualPixels); return image; @@ -478,7 +477,7 @@ namespace SixLabors.ImageSharp.Tests public static ImageFrame ComparePixelBufferTo(this ImageFrame imageFrame, TPixel expectedPixel) where TPixel : unmanaged, IPixel { - Span actualPixels = imageFrame.GetPixelSpan(); + Assert.True(imageFrame.TryGetSinglePixelSpan(out Span actualPixels)); for (int i = 0; i < actualPixels.Length; i++) { @@ -493,8 +492,7 @@ namespace SixLabors.ImageSharp.Tests Span expectedPixels) where TPixel : unmanaged, IPixel { - Span actual = image.GetPixelSpan(); - + Assert.True(image.TryGetSinglePixelSpan(out Span actual)); Assert.True(expectedPixels.Length == actual.Length, "Buffer sizes are not equal!"); for (int i = 0; i < expectedPixels.Length; i++) @@ -677,8 +675,7 @@ namespace SixLabors.ImageSharp.Tests { var image = new Image(buffer.Width, buffer.Height); - Span pixels = image.Frames.RootFrame.GetPixelSpan(); - + Assert.True(image.Frames.RootFrame.TryGetSinglePixelSpan(out Span pixels)); Span bufferSpan = buffer.GetSingleSpan(); for (int i = 0; i < bufferSpan.Length; i++) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 3a1fbd1952..8af20a94fd 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -14,6 +14,7 @@ using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using Xunit; namespace SixLabors.ImageSharp.Tests { @@ -160,7 +161,7 @@ namespace SixLabors.ImageSharp.Tests ImageComparer comparer = null) where TPixel : unmanaged, IPixel { - comparer??= ImageComparer.Exact; + comparer ??= ImageComparer.Exact; using Image expected = provider.GetImage(); int width = expected.Width; expected.Mutate(process); @@ -277,7 +278,8 @@ namespace SixLabors.ImageSharp.Tests using (Image image0 = provider.GetImage()) { - var mmg = TestMemoryManager.CreateAsCopyOf(image0.GetPixelSpan()); + Assert.True(image0.TryGetSinglePixelSpan(out Span imageSpan)); + var mmg = TestMemoryManager.CreateAsCopyOf(imageSpan); using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) { From 404c08600764a017b6776a23dcbf266a5e291d99 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 13 Apr 2020 15:31:58 +0200 Subject: [PATCH 109/213] Improved codegen for throw path in MemoryGroup.Owned --- .../DiscontiguousBuffers/MemoryGroup{T}.Owned.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index b42b90d286..276dee7ed0 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory { @@ -69,14 +70,21 @@ namespace SixLabors.ImageSharp.Memory this.IsValid = false; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void EnsureNotDisposed() { - if (this.memoryOwners == null) + if (this.memoryOwners is null) { - throw new ObjectDisposedException(nameof(MemoryGroup)); + ThrowObjectDisposedException(); } } + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowObjectDisposedException() + { + throw new ObjectDisposedException(nameof(MemoryGroup)); + } + internal static void SwapContents(Owned a, Owned b) { a.EnsureNotDisposed(); From f1f3cb759b35f899621d712758fce00989b87c93 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 13 Apr 2020 15:32:08 +0200 Subject: [PATCH 110/213] Removed unnecessary using directives --- .../Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs index f1fe4ed9c5..48da903102 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs @@ -2,9 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Collections.Generic; -using System.Linq; namespace SixLabors.ImageSharp.Memory { From c2ec5c45a44f4e29aa9f3be7d3c52fa42e82ad67 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 13 Apr 2020 15:37:02 +0200 Subject: [PATCH 111/213] Removed unnecessary iterator block --- .../DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs index 48da903102..493fe6e336 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs @@ -26,10 +26,13 @@ namespace SixLabors.ImageSharp.Memory public override IEnumerator> GetEnumerator() { - for (int i = 0; i < this.source.Length; i++) - { - yield return this.source[i]; - } + /* The runtime sees the Array class as if it implemented the + * type-generic collection interfaces explicitly, so here we + * can just cast the source array to IList> (or to + * an equivalent type), and invoke the generic GetEnumerator + * method directly from that interface reference. This saves + * having to create our own iterator block here. */ + return ((IList>)this.source).GetEnumerator(); } public override void Dispose() From 2ec776812f739f62c77384f008486b3d927ceab1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 13 Apr 2020 14:54:45 +0100 Subject: [PATCH 112/213] Add argument docs and negative tests --- src/ImageSharp/ImageFrame{TPixel}.cs | 1 + src/ImageSharp/Image{TPixel}.cs | 1 + .../Image/LargeImageIntegrationTests.cs | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 0c00349f2b..0171f3d07f 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -173,6 +173,7 @@ namespace SixLabors.ImageSharp /// /// The row. /// The + /// Thrown when row index is out of range. public Span GetPixelRowSpan(int rowIndex) { Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 20be772e2e..f6173db972 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -169,6 +169,7 @@ namespace SixLabors.ImageSharp /// /// The row. /// The + /// Thrown when row index is out of range. public Span GetPixelRowSpan(int rowIndex) { Guard.MustBeGreaterThanOrEqualTo(rowIndex, 0, nameof(rowIndex)); diff --git a/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs b/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs index c8a8baf1d1..7352ddd7df 100644 --- a/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs +++ b/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using Xunit; @@ -17,5 +18,15 @@ namespace SixLabors.ImageSharp.Tests image.Mutate(c => c.Resize(1000, 1000)); image.DebugSave(provider); } + + [Theory] + [WithBasicTestPatternImages(width: 10, height: 10, PixelTypes.Rgba32)] + public void GetSingleSpan(TestImageProvider provider) + { + provider.LimitAllocatorBufferCapacity().InPixels(10); + using Image image = provider.GetImage(); + Assert.False(image.TryGetSinglePixelSpan(out Span imageSpan)); + Assert.False(image.Frames.RootFrame.TryGetSinglePixelSpan(out Span imageFrameSpan)); + } } } From a7d6acfcc28b94934765e50a3f0a17865e9ead2f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 13 Apr 2020 16:08:25 +0200 Subject: [PATCH 113/213] Added MemoryGroupEnumerator struct --- .../MemoryGroupEnumerator{T}.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs new file mode 100644 index 0000000000..2c2ae90906 --- /dev/null +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.Memory.DiscontiguousBuffers +{ + /// + /// A value-type enumerator for instances. + /// + /// The element type. + public ref struct MemoryGroupEnumerator + where T : struct + { + private readonly MemoryGroup memoryGroup; + private readonly int count; + private int index; + + [MethodImpl(InliningOptions.ShortMethod)] + internal MemoryGroupEnumerator(MemoryGroup.Owned memoryGroup) + { + this.memoryGroup = memoryGroup; + this.count = memoryGroup.Count; + this.index = -1; + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal MemoryGroupEnumerator(MemoryGroup.Consumed memoryGroup) + { + this.memoryGroup = memoryGroup; + this.count = memoryGroup.Count; + this.index = -1; + } + + /// + public Memory Current + { + [MethodImpl(InliningOptions.ShortMethod)] + get => this.memoryGroup[this.index]; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool MoveNext() + { + int index = this.index + 1; + + if (index < this.count) + { + this.index = index; + + return true; + } + + return false; + } + } +} From aae14cf6ae97aac70da3909e149dab49ae1bda01 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 13 Apr 2020 16:35:10 +0200 Subject: [PATCH 114/213] Added overload for MemoryGroupView in MemoryGroupEnumerator --- .../MemoryGroupEnumerator{T}.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs index 2c2ae90906..1bc44e33e1 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs @@ -2,18 +2,20 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.ComponentModel; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.Memory.DiscontiguousBuffers +namespace SixLabors.ImageSharp.Memory { /// /// A value-type enumerator for instances. /// /// The element type. + [EditorBrowsable(EditorBrowsableState.Never)] public ref struct MemoryGroupEnumerator where T : struct { - private readonly MemoryGroup memoryGroup; + private readonly IMemoryGroup memoryGroup; private readonly int count; private int index; @@ -33,6 +35,14 @@ namespace SixLabors.ImageSharp.Memory.DiscontiguousBuffers this.index = -1; } + [MethodImpl(InliningOptions.ShortMethod)] + internal MemoryGroupEnumerator(MemoryGroupView memoryGroup) + { + this.memoryGroup = memoryGroup; + this.count = memoryGroup.Count; + this.index = -1; + } + /// public Memory Current { From 989300ecdf1aa61e00f0acb7ceaf5ba1d46f6481 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 13 Apr 2020 16:38:39 +0200 Subject: [PATCH 115/213] Added optimized IMemoryGroup.GetEnumerator() method --- .../DiscontiguousBuffers/IMemoryGroup{T}.cs | 10 ++++++++ .../MemoryGroupView{T}.cs | 15 ++++++++++-- .../MemoryGroup{T}.Consumed.cs | 23 +++++++++++++++---- .../MemoryGroup{T}.Owned.cs | 19 +++++++++++---- .../DiscontiguousBuffers/MemoryGroup{T}.cs | 16 ++++++++++--- 5 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs index 89aca914d0..3bb6b8d336 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs @@ -33,5 +33,15 @@ namespace SixLabors.ImageSharp.Memory /// the image buffers internally. /// bool IsValid { get; } + + /// + /// Returns a value-type implementing an allocation-free enumerator of the memory groups in the current + /// instance. The return type shouldn't be used directly: just use a block on + /// the instance in use and the C# compiler will automatically invoke this + /// method behind the scenes. This method takes precedence over the + /// implementation, which is still available when casting to one of the underlying interfaces. + /// + /// A new instance mapping the current values in use. + new MemoryGroupEnumerator GetEnumerator(); } } diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs index 3f39ba12f5..1698f08d17 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory { @@ -37,6 +38,7 @@ namespace SixLabors.ImageSharp.Memory public int Count { + [MethodImpl(InliningOptions.ShortMethod)] get { this.EnsureIsValid(); @@ -73,7 +75,15 @@ namespace SixLabors.ImageSharp.Memory } } - public IEnumerator> GetEnumerator() + /// + [MethodImpl(InliningOptions.ShortMethod)] + public MemoryGroupEnumerator GetEnumerator() + { + return new MemoryGroupEnumerator(this); + } + + /// + IEnumerator> IEnumerable>.GetEnumerator() { this.EnsureIsValid(); for (int i = 0; i < this.Count; i++) @@ -82,7 +92,8 @@ namespace SixLabors.ImageSharp.Memory } } - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); + /// + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable>)this).GetEnumerator(); internal void Invalidate() { diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs index 493fe6e336..1dfbaea932 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs @@ -3,13 +3,16 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory { internal abstract partial class MemoryGroup { - // Analogous to the "consumed" variant of MemorySource - private sealed class Consumed : MemoryGroup + /// + /// A implementation that consumes the underlying memory buffers. + /// + public sealed class Consumed : MemoryGroup, IEnumerable> { private readonly Memory[] source; @@ -20,11 +23,23 @@ namespace SixLabors.ImageSharp.Memory this.View = new MemoryGroupView(this); } - public override int Count => this.source.Length; + public override int Count + { + [MethodImpl(InliningOptions.ShortMethod)] + get => this.source.Length; + } public override Memory this[int index] => this.source[index]; - public override IEnumerator> GetEnumerator() + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override MemoryGroupEnumerator GetEnumerator() + { + return new MemoryGroupEnumerator(this); + } + + /// + IEnumerator> IEnumerable>.GetEnumerator() { /* The runtime sees the Array class as if it implemented the * type-generic collection interfaces explicitly, so here we diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index 276dee7ed0..5a86ac4268 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -9,10 +9,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory { - // Analogous to the "owned" variant of MemorySource internal abstract partial class MemoryGroup { - private sealed class Owned : MemoryGroup + /// + /// A implementation that owns the underlying memory buffers. + /// + public sealed class Owned : MemoryGroup, IEnumerable> { private IMemoryOwner[] memoryOwners; @@ -30,6 +32,7 @@ namespace SixLabors.ImageSharp.Memory public override int Count { + [MethodImpl(InliningOptions.ShortMethod)] get { this.EnsureNotDisposed(); @@ -46,7 +49,15 @@ namespace SixLabors.ImageSharp.Memory } } - public override IEnumerator> GetEnumerator() + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override MemoryGroupEnumerator GetEnumerator() + { + return new MemoryGroupEnumerator(this); + } + + /// + IEnumerator> IEnumerable>.GetEnumerator() { this.EnsureNotDisposed(); return this.memoryOwners.Select(mo => mo.Memory).GetEnumerator(); @@ -70,7 +81,7 @@ namespace SixLabors.ImageSharp.Memory this.IsValid = false; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void EnsureNotDisposed() { if (this.memoryOwners is null) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 38de57b4ac..6fd93f12ea 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -6,7 +6,6 @@ using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Memory.Internals; namespace SixLabors.ImageSharp.Memory { @@ -48,10 +47,21 @@ namespace SixLabors.ImageSharp.Memory public abstract void Dispose(); /// - public abstract IEnumerator> GetEnumerator(); + public abstract MemoryGroupEnumerator GetEnumerator(); /// - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); + IEnumerator> IEnumerable>.GetEnumerator() + { + /* This method is implemented in each derived class. + * Implementing the method here as non-abstract and throwing, + * then reimplementing it explicitly in each derived class, is + * a workaround for the lack of support for abstract explicit + * interface method implementations in C#. */ + throw new NotImplementedException($"The type {this.GetType()} needs to override IEnumerable>.GetEnumerator()"); + } + + /// + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable>)this).GetEnumerator(); /// /// Creates a new memory group, allocating it's buffers with the provided allocator. From c237de595c40a251e9daa6f8a373ac45505755c0 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 13 Apr 2020 17:13:02 +0200 Subject: [PATCH 116/213] Added new tests for all IMemoryGroup enumerators --- .../DiscontiguousBuffers/MemoryGroupTests.cs | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs index 694c4d32f6..2a5dafb27d 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs @@ -1,8 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Buffers; +using System.Collections; +using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; @@ -165,7 +167,7 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers } [Fact] - public void Fill() + public void FillWithFastEnumerator() { using MemoryGroup group = this.CreateTestGroup(100, 10, true); group.Fill(42); @@ -177,6 +179,34 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers } } + [Fact] + public void FillWithSlowGenericEnumerator() + { + using MemoryGroup group = this.CreateTestGroup(100, 10, true); + group.Fill(42); + + int[] expectedRow = Enumerable.Repeat(42, 10).ToArray(); + IReadOnlyList> groupAsList = group; + foreach (Memory memory in groupAsList) + { + Assert.True(memory.Span.SequenceEqual(expectedRow)); + } + } + + [Fact] + public void FillWithSlowEnumerator() + { + using MemoryGroup group = this.CreateTestGroup(100, 10, true); + group.Fill(42); + + int[] expectedRow = Enumerable.Repeat(42, 10).ToArray(); + IEnumerable groupAsList = group; + foreach (Memory memory in groupAsList) + { + Assert.True(memory.Span.SequenceEqual(expectedRow)); + } + } + [Fact] public void Clear() { From ee96011669a4a7848bcb1f4a58927015bdb6cf6d Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 14 Apr 2020 11:04:04 +0200 Subject: [PATCH 117/213] Add support for reading IPTC metadata --- .../Components/Decoder/ProfileResolver.cs | 24 ++ .../Formats/Jpeg/JpegDecoderCore.cs | 120 +++++- src/ImageSharp/Metadata/ImageMetadata.cs | 6 + .../Metadata/Profiles/IPTC/IptcProfile.cs | 204 ++++++++++ .../Metadata/Profiles/IPTC/IptcTag.cs | 351 ++++++++++++++++++ .../Metadata/Profiles/IPTC/IptcValue.cs | 167 +++++++++ .../Metadata/Profiles/IPTC/README.md | 9 + 7 files changed, 872 insertions(+), 9 deletions(-) create mode 100644 src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs create mode 100644 src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs create mode 100644 src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs create mode 100644 src/ImageSharp/Metadata/Profiles/IPTC/README.md diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs index 87b486ea65..325d7780ae 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs @@ -28,6 +28,30 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder (byte)'I', (byte)'L', (byte)'E', (byte)'\0' }; + /// + /// Gets the adobe photoshop APP13 marker which can contain IPTC meta data. + /// + public static ReadOnlySpan AdobePhotoshopApp13Marker => new[] + { + (byte)'P', (byte)'h', (byte)'o', (byte)'t', (byte)'o', (byte)'s', (byte)'h', (byte)'o', (byte)'p', (byte)' ', (byte)'3', (byte)'.', (byte)'0', (byte)'\0' + }; + + /// + /// Gets the 8BIM marker, which signals the start of a adobe specific image resource block. + /// + public static ReadOnlySpan AdobeImageResourceBlockMarker => new[] + { + (byte)'8', (byte)'B', (byte)'I', (byte)'M' + }; + + /// + /// Gets a IPTC Image resource ID. + /// + public static ReadOnlySpan AdobeIptcMarker => new[] + { + (byte)4, (byte)4 + }; + /// /// Gets the EXIF specific markers. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 951fec1d4c..46f0e694e0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -14,6 +14,7 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; +using SixLabors.ImageSharp.Metadata.Profiles.Iptc; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Jpeg @@ -46,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private readonly byte[] markerBuffer = new byte[2]; /// - /// The DC Huffman tables + /// The DC Huffman tables. /// private HuffmanTable[] dcHuffmanTables; @@ -56,37 +57,47 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private HuffmanTable[] acHuffmanTables; /// - /// The reset interval determined by RST markers + /// The reset interval determined by RST markers. /// private ushort resetInterval; /// - /// Whether the image has an EXIF marker + /// Whether the image has an EXIF marker. /// private bool isExif; /// - /// Contains exif data + /// Contains exif data. /// private byte[] exifData; /// - /// Whether the image has an ICC marker + /// Whether the image has an ICC marker. /// private bool isIcc; /// - /// Contains ICC data + /// Contains ICC data. /// private byte[] iccData; /// - /// Contains information about the JFIF marker + /// Whether the image has a IPTC data. + /// + private bool isIptc; + + /// + /// Contains IPTC data. + /// + private byte[] iptcData; + + /// + /// Contains information about the JFIF marker. /// private JFifMarker jFif; /// - /// Contains information about the Adobe marker + /// Contains information about the Adobe marker. /// private AdobeMarker adobe; @@ -213,6 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.ParseStream(stream); this.InitExifProfile(); this.InitIccProfile(); + this.InitIptcProfile(); this.InitDerivedMetadataProperties(); return this.PostProcessIntoImage(); } @@ -226,6 +238,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.ParseStream(stream, true); this.InitExifProfile(); this.InitIccProfile(); + this.InitIptcProfile(); this.InitDerivedMetadataProperties(); return new ImageInfo(new PixelTypeInfo(this.BitsPerPixel), this.ImageWidth, this.ImageHeight, this.Metadata); @@ -344,10 +357,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg case JpegConstants.Markers.APP10: case JpegConstants.Markers.APP11: case JpegConstants.Markers.APP12: - case JpegConstants.Markers.APP13: this.InputStream.Skip(remaining); break; + case JpegConstants.Markers.APP13: + this.ProcessApp13Marker(remaining); + break; + case JpegConstants.Markers.APP14: this.ProcessApp14Marker(remaining); break; @@ -437,6 +453,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } } + /// + /// Initializes the IPTC profile. + /// + private void InitIptcProfile() + { + if (this.isIptc) + { + var profile = new IptcProfile(this.iptcData); + this.Metadata.IptcProfile = profile; + } + } + /// /// Assigns derived metadata properties to , eg. horizontal and vertical resolution if it has a JFIF header. /// @@ -582,6 +610,80 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } } + /// + /// Processes a App13 marker, which contains IPTC data stored with Adobe Photoshop. + /// The content of an APP13 segment is formed by an identifier string followed by a sequence of resource data blocks. + /// + /// The remaining bytes in the segment block. + private void ProcessApp13Marker(int remaining) + { + if (remaining < ProfileResolver.AdobePhotoshopApp13Marker.Length || this.IgnoreMetadata) + { + this.InputStream.Skip(remaining); + return; + } + + var identifier = new byte[ProfileResolver.AdobePhotoshopApp13Marker.Length]; + this.InputStream.Read(identifier, 0, identifier.Length); + remaining -= identifier.Length; + if (ProfileResolver.IsProfile(identifier, ProfileResolver.AdobePhotoshopApp13Marker)) + { + var resourceBlockData = new byte[remaining]; + this.InputStream.Read(resourceBlockData, 0, remaining); + Span blockDataSpan = resourceBlockData.AsSpan(); + + while (blockDataSpan.Length > 10) + { + if (!ProfileResolver.IsProfile(blockDataSpan.Slice(0, 4), ProfileResolver.AdobeImageResourceBlockMarker)) + { + return; + } + + blockDataSpan = blockDataSpan.Slice(4); + Span imageResourceBlockId = blockDataSpan.Slice(0, 2); + if (ProfileResolver.IsProfile(imageResourceBlockId, ProfileResolver.AdobeIptcMarker)) + { + var resourceBlockNameLength = ReadImageResourceNameLength(blockDataSpan); + var resourceDataSize = ReadResourceDataLength(blockDataSpan, resourceBlockNameLength); + this.isIptc = true; + this.iptcData = blockDataSpan.Slice(2 + resourceBlockNameLength + 4, resourceDataSize).ToArray(); + break; + } + else + { + var resourceBlockNameLength = ReadImageResourceNameLength(blockDataSpan); + var resourceDataSize = ReadResourceDataLength(blockDataSpan, resourceBlockNameLength); + blockDataSpan = blockDataSpan.Slice(2 + resourceBlockNameLength + 4 + resourceDataSize); + } + } + } + } + + /// + /// Reads the adobe image resource block name: a Pascal string (padded to make size even). + /// + /// The span holding the block resource data. + /// The length of the name. + [MethodImpl(InliningOptions.ShortMethod)] + private static int ReadImageResourceNameLength(Span blockDataSpan) + { + byte nameLength = blockDataSpan[2]; + var nameDataSize = nameLength == 0 ? 2 : nameLength; + return nameDataSize; + } + + /// + /// Reads the length of a adobe image resource data block. + /// + /// The span holding the block resource data. + /// The length of the block name. + /// The block length. + [MethodImpl(InliningOptions.ShortMethod)] + private static int ReadResourceDataLength(Span blockDataSpan, int resourceBlockNameLength) + { + return BinaryPrimitives.ReadInt32BigEndian(blockDataSpan.Slice(2 + resourceBlockNameLength, 4)); + } + /// /// Processes the application header containing the Adobe identifier /// which stores image encoding information for DCT filters. diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs index b3751bfbdc..4fa07592e0 100644 --- a/src/ImageSharp/Metadata/ImageMetadata.cs +++ b/src/ImageSharp/Metadata/ImageMetadata.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; +using SixLabors.ImageSharp.Metadata.Profiles.Iptc; namespace SixLabors.ImageSharp.Metadata { @@ -122,6 +123,11 @@ namespace SixLabors.ImageSharp.Metadata /// public IccProfile IccProfile { get; set; } + /// + /// Gets or sets the iptc profile. + /// + public IptcProfile IptcProfile { get; set; } + /// /// Gets the metadata value associated with the specified key. /// diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs new file mode 100644 index 0000000000..2b0281b3b9 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -0,0 +1,204 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc +{ + /// + /// Class that can be used to access an Iptc profile. + /// + /// This source code is from the Magick.Net project: + /// https://github.com/dlemstra/Magick.NET/tree/master/src/Magick.NET/Shared/Profiles/Iptc/IptcProfile.cs + /// + public sealed class IptcProfile + { + private Collection values; + + private byte[] data; + + /// + /// Initializes a new instance of the class. + /// + public IptcProfile() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The byte array to read the iptc profile from. + public IptcProfile(byte[] data) + { + this.data = data; + } + + /// + /// Gets the values of this iptc profile. + /// + public IEnumerable Values + { + get + { + this.Initialize(); + return this.values; + } + } + + /// + /// Returns the value with the specified tag. + /// + /// The tag of the iptc value. + /// The value with the specified tag. + public IptcValue GetValue(IptcTag tag) + { + foreach (IptcValue iptcValue in this.Values) + { + if (iptcValue.Tag == tag) + { + return iptcValue; + } + } + + return null; + } + + /// + /// Removes the value with the specified tag. + /// + /// The tag of the iptc value. + /// True when the value was fount and removed. + public bool RemoveValue(IptcTag tag) + { + this.Initialize(); + + for (int i = 0; i < this.values.Count; i++) + { + if (this.values[i].Tag == tag) + { + this.values.RemoveAt(i); + return true; + } + } + + return false; + } + + /// + /// Changes the encoding for all the values. + /// + /// The encoding to use when storing the bytes. + public void SetEncoding(Encoding encoding) + { + Guard.NotNull(encoding, nameof(encoding)); + + foreach (IptcValue value in this.Values) + { + value.Encoding = encoding; + } + } + + /// + /// Sets the value of the specified tag. + /// + /// The tag of the iptc value. + /// The encoding to use when storing the bytes. + /// The value. + public void SetValue(IptcTag tag, Encoding encoding, string value) + { + Guard.NotNull(encoding, nameof(encoding)); + + foreach (IptcValue iptcValue in this.Values) + { + if (iptcValue.Tag == tag) + { + iptcValue.Encoding = encoding; + iptcValue.Value = value; + return; + } + } + + this.values.Add(new IptcValue(tag, encoding, value)); + } + + /// + /// Sets the value of the specified tag. + /// + /// The tag of the iptc value. + /// The value. + public void SetValue(IptcTag tag, string value) => this.SetValue(tag, Encoding.UTF8, value); + + /// + /// Updates the data of the profile. + /// + public void UpdateData() + { + var length = 0; + foreach (IptcValue value in this.Values) + { + length += value.Length + 5; + } + + this.data = new byte[length]; + + int i = 0; + foreach (IptcValue value in this.Values) + { + this.data[i++] = 28; + this.data[i++] = 2; + this.data[i++] = (byte)value.Tag; + this.data[i++] = (byte)(value.Length >> 8); + this.data[i++] = (byte)value.Length; + if (value.Length > 0) + { + Buffer.BlockCopy(value.ToByteArray(), 0, this.data, i, value.Length); + i += value.Length; + } + } + } + + private void Initialize() + { + if (this.values != null) + { + return; + } + + this.values = new Collection(); + + if (this.data == null || this.data[0] != 0x1c) + { + return; + } + + int i = 0; + while (i + 4 < this.data.Length) + { + if (this.data[i++] != 28) + { + continue; + } + + i++; + + var tag = (IptcTag)this.data[i++]; + + int count = BinaryPrimitives.ReadInt16BigEndian(this.data.AsSpan(i, 2)); + i += 2; + + var iptcData = new byte[count]; + if ((count > 0) && (i + count <= this.data.Length)) + { + Buffer.BlockCopy(this.data, i, iptcData, 0, count); + this.values.Add(new IptcValue(tag, iptcData)); + } + + i += count; + } + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs new file mode 100644 index 0000000000..3e6da0e092 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs @@ -0,0 +1,351 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc +{ + /// + /// All iptc tags. + /// + public enum IptcTag + { + /// + /// Unknown + /// + Unknown = -1, + + /// + /// Record version + /// + RecordVersion = 0, + + /// + /// Object type + /// + ObjectType = 3, + + /// + /// Object attribute + /// + ObjectAttribute = 4, + + /// + /// Title + /// + Title = 5, + + /// + /// Edit status + /// + EditStatus = 7, + + /// + /// Editorial update + /// + EditorialUpdate = 8, + + /// + /// Priority + /// + Priority = 10, + + /// + /// Category + /// + Category = 15, + + /// + /// Supplemental categories + /// + SupplementalCategories = 20, + + /// + /// Fixture identifier + /// + FixtureIdentifier = 22, + + /// + /// Keyword + /// + Keyword = 25, + + /// + /// Location code + /// + LocationCode = 26, + + /// + /// Location name + /// + LocationName = 27, + + /// + /// Release date + /// + ReleaseDate = 30, + + /// + /// Release time + /// + ReleaseTime = 35, + + /// + /// Expiration date + /// + ExpirationDate = 37, + + /// + /// Expiration time + /// + ExpirationTime = 38, + + /// + /// Special instructions + /// + SpecialInstructions = 40, + + /// + /// Action advised + /// + ActionAdvised = 42, + + /// + /// Reference service + /// + ReferenceService = 45, + + /// + /// Reference date + /// + ReferenceDate = 47, + + /// + /// ReferenceNumber + /// + ReferenceNumber = 50, + + /// + /// Created date + /// + CreatedDate = 55, + + /// + /// Created time + /// + CreatedTime = 60, + + /// + /// Digital creation date + /// + DigitalCreationDate = 62, + + /// + /// Digital creation time + /// + DigitalCreationTime = 63, + + /// + /// Originating program + /// + OriginatingProgram = 65, + + /// + /// Program version + /// + ProgramVersion = 70, + + /// + /// Object cycle + /// + ObjectCycle = 75, + + /// + /// Byline + /// + Byline = 80, + + /// + /// Byline title + /// + BylineTitle = 85, + + /// + /// City + /// + City = 90, + + /// + /// Sub location + /// + SubLocation = 92, + + /// + /// Province/State + /// + ProvinceState = 95, + + /// + /// Country code + /// + CountryCode = 100, + + /// + /// Country + /// + Country = 101, + + /// + /// Original transmission reference + /// + OriginalTransmissionReference = 103, + + /// + /// Headline + /// + Headline = 105, + + /// + /// Credit + /// + Credit = 110, + + /// + /// Source + /// + Source = 115, + + /// + /// Copyright notice + /// + CopyrightNotice = 116, + + /// + /// Contact + /// + Contact = 118, + + /// + /// Caption + /// + Caption = 120, + + /// + /// Local caption + /// + LocalCaption = 121, + + /// + /// Caption writer + /// + CaptionWriter = 122, + + /// + /// Image type + /// + ImageType = 130, + + /// + /// Image orientation + /// + ImageOrientation = 131, + + /// + /// Custom field 1 + /// + CustomField1 = 200, + + /// + /// Custom field 2 + /// + CustomField2 = 201, + + /// + /// Custom field 3 + /// + CustomField3 = 202, + + /// + /// Custom field 4 + /// + CustomField4 = 203, + + /// + /// Custom field 5 + /// + CustomField5 = 204, + + /// + /// Custom field 6 + /// + CustomField6 = 205, + + /// + /// Custom field 7 + /// + CustomField7 = 206, + + /// + /// Custom field 8 + /// + CustomField8 = 207, + + /// + /// Custom field 9 + /// + CustomField9 = 208, + + /// + /// Custom field 10 + /// + CustomField10 = 209, + + /// + /// Custom field 11 + /// + CustomField11 = 210, + + /// + /// Custom field 12 + /// + CustomField12 = 211, + + /// + /// Custom field 13 + /// + CustomField13 = 212, + + /// + /// Custom field 14 + /// + CustomField14 = 213, + + /// + /// Custom field 15 + /// + CustomField15 = 214, + + /// + /// Custom field 16 + /// + CustomField16 = 215, + + /// + /// Custom field 17 + /// + CustomField17 = 216, + + /// + /// Custom field 18 + /// + CustomField18 = 217, + + /// + /// Custom field 19 + /// + CustomField19 = 218, + + /// + /// Custom field 20 + /// + CustomField20 = 219, + } +} diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs new file mode 100644 index 0000000000..c23a7793e4 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs @@ -0,0 +1,167 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Text; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc +{ + /// + /// A value of the iptc profile. + /// + public sealed class IptcValue + { + private byte[] data; + private Encoding encoding; + + internal IptcValue(IptcTag tag, byte[] value) + { + Guard.NotNull(value, nameof(value)); + + this.Tag = tag; + this.data = value; + this.encoding = Encoding.UTF8; + } + + internal IptcValue(IptcTag tag, Encoding encoding, string value) + { + this.Tag = tag; + this.encoding = encoding; + this.Value = value; + } + + /// + /// Gets or sets the encoding to use for the Value. + /// + public Encoding Encoding + { + get => this.encoding; + set + { + if (value != null) + { + this.encoding = value; + } + } + } + + /// + /// Gets the tag of the iptc value. + /// + public IptcTag Tag { get; } + + /// + /// Gets or sets the value. + /// + public string Value + { + get => this.encoding.GetString(this.data); + set + { + if (string.IsNullOrEmpty(value)) + { + this.data = new byte[0]; + } + else + { + this.data = this.encoding.GetBytes(value); + } + } + } + + /// + /// Gets the length of the value. + /// + public int Length => this.data.Length; + + /// + /// Determines whether the specified object is equal to the current . + /// + /// The object to compare this with. + /// True when the specified object is equal to the current . + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + + return this.Equals(obj as IptcValue); + } + + /// + /// Determines whether the specified iptc value is equal to the current . + /// + /// The iptc value to compare this with. + /// True when the specified iptc value is equal to the current . + public bool Equals(IptcValue other) + { + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (this.Tag != other.Tag) + { + return false; + } + + byte[] data = other.ToByteArray(); + + if (this.data.Length != data.Length) + { + return false; + } + + for (int i = 0; i < this.data.Length; i++) + { + if (this.data[i] != data[i]) + { + return false; + } + } + + return true; + } + + /// + /// Serves as a hash of this type. + /// + /// A hash code for the current instance. + public override int GetHashCode() => HashCode.Combine(this.data, this.Tag); + + /// + /// Converts this instance to a byte array. + /// + /// A array. + public byte[] ToByteArray() + { + var result = new byte[this.data.Length]; + this.data.CopyTo(result, 0); + return result; + } + + /// + /// Returns a string that represents the current value. + /// + /// A string that represents the current value. + public override string ToString() => this.Value; + + /// + /// Returns a string that represents the current value with the specified encoding. + /// + /// The encoding to use. + /// A string that represents the current value with the specified encoding. + public string ToString(Encoding enc) + { + Guard.NotNull(enc, nameof(enc)); + + return enc.GetString(this.data); + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/README.md b/src/ImageSharp/Metadata/Profiles/IPTC/README.md new file mode 100644 index 0000000000..0b0efc967d --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/IPTC/README.md @@ -0,0 +1,9 @@ +IPTC source code is from [Magick.NET](https://github.com/dlemstra/Magick.NET) + +Information about IPTC can be found here in the folowing sources: + +- [metacpan.org, APP13-segment](https://metacpan.org/pod/Image::MetaData::JPEG::Structures#Structure-of-a-Photoshop-style-APP13-segment) + +- [iptc.org](https://www.iptc.org/std/photometadata/documentation/userguide/) + +- [Adobe File Formats Specification](http://oldschoolprg.x10.mx/downloads/ps6ffspecsv2.pdf) \ No newline at end of file From 14312962b264b4c517c6f460f377db0ed7623035 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 14 Apr 2020 16:23:14 +0200 Subject: [PATCH 118/213] Add unit tests for reading IPTC profile --- src/ImageSharp/Metadata/ImageMetadata.cs | 1 + .../Metadata/Profiles/Exif/ExifProfile.cs | 3 + .../Metadata/Profiles/IPTC/IptcProfile.cs | 64 +++++++++---- .../Metadata/Profiles/IPTC/IptcValue.cs | 21 ++++- .../Profiles/IPTC/IptcProfileTests.cs | 88 ++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Jpg/baseline/iptc.jpg | Bin 0 -> 18611 bytes 7 files changed, 159 insertions(+), 19 deletions(-) create mode 100644 tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs create mode 100644 tests/Images/Input/Jpg/baseline/iptc.jpg diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs index 4fa07592e0..716e89e68d 100644 --- a/src/ImageSharp/Metadata/ImageMetadata.cs +++ b/src/ImageSharp/Metadata/ImageMetadata.cs @@ -66,6 +66,7 @@ namespace SixLabors.ImageSharp.Metadata this.ExifProfile = other.ExifProfile?.DeepClone(); this.IccProfile = other.IccProfile?.DeepClone(); + this.IptcProfile = other.IptcProfile?.DeepClone(); } /// diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs index 11d0bd01b0..29c21d6113 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs @@ -57,8 +57,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// by making a copy from another EXIF profile. /// /// The other EXIF profile, where the clone should be made from. + /// is null.> private ExifProfile(ExifProfile other) { + Guard.NotNull(other, nameof(other)); + this.Parts = other.Parts; this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index 2b0281b3b9..57704949c0 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -15,16 +15,15 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// This source code is from the Magick.Net project: /// https://github.com/dlemstra/Magick.NET/tree/master/src/Magick.NET/Shared/Profiles/Iptc/IptcProfile.cs /// - public sealed class IptcProfile + public sealed class IptcProfile : IDeepCloneable { private Collection values; - private byte[] data; - /// /// Initializes a new instance of the class. /// public IptcProfile() + : this((byte[])null) { } @@ -34,9 +33,35 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// The byte array to read the iptc profile from. public IptcProfile(byte[] data) { - this.data = data; + this.Data = data; + } + + private IptcProfile(IptcProfile other) + { + Guard.NotNull(other, nameof(other)); + + if (other.values != null) + { + this.values = new Collection(); + + foreach (IptcValue value in other.Values) + { + this.values.Add(value.DeepClone()); + } + } + + if (other.Data != null) + { + this.Data = new byte[other.Data.Length]; + other.Data.AsSpan().CopyTo(this.Data); + } } + /// + /// Gets the byte data of the IPTC profile. + /// + public byte[] Data { get; private set; } + /// /// Gets the values of this iptc profile. /// @@ -49,6 +74,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc } } + /// + public IptcProfile DeepClone() => new IptcProfile(this); + /// /// Returns the value with the specified tag. /// @@ -143,19 +171,19 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc length += value.Length + 5; } - this.data = new byte[length]; + this.Data = new byte[length]; int i = 0; foreach (IptcValue value in this.Values) { - this.data[i++] = 28; - this.data[i++] = 2; - this.data[i++] = (byte)value.Tag; - this.data[i++] = (byte)(value.Length >> 8); - this.data[i++] = (byte)value.Length; + this.Data[i++] = 28; + this.Data[i++] = 2; + this.Data[i++] = (byte)value.Tag; + this.Data[i++] = (byte)(value.Length >> 8); + this.Data[i++] = (byte)value.Length; if (value.Length > 0) { - Buffer.BlockCopy(value.ToByteArray(), 0, this.data, i, value.Length); + Buffer.BlockCopy(value.ToByteArray(), 0, this.Data, i, value.Length); i += value.Length; } } @@ -170,30 +198,30 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc this.values = new Collection(); - if (this.data == null || this.data[0] != 0x1c) + if (this.Data == null || this.Data[0] != 0x1c) { return; } int i = 0; - while (i + 4 < this.data.Length) + while (i + 4 < this.Data.Length) { - if (this.data[i++] != 28) + if (this.Data[i++] != 28) { continue; } i++; - var tag = (IptcTag)this.data[i++]; + var tag = (IptcTag)this.Data[i++]; - int count = BinaryPrimitives.ReadInt16BigEndian(this.data.AsSpan(i, 2)); + int count = BinaryPrimitives.ReadInt16BigEndian(this.Data.AsSpan(i, 2)); i += 2; var iptcData = new byte[count]; - if ((count > 0) && (i + count <= this.data.Length)) + if ((count > 0) && (i + count <= this.Data.Length)) { - Buffer.BlockCopy(this.data, i, iptcData, 0, count); + Buffer.BlockCopy(this.Data, i, iptcData, 0, count); this.values.Add(new IptcValue(tag, iptcData)); } diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs index c23a7793e4..a5977fd274 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs @@ -9,11 +9,27 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// /// A value of the iptc profile. /// - public sealed class IptcValue + public sealed class IptcValue : IDeepCloneable { private byte[] data; private Encoding encoding; + internal IptcValue(IptcValue other) + { + if (other.data != null) + { + this.data = new byte[other.data.Length]; + other.data.AsSpan().CopyTo(this.data); + } + + if (other.Encoding != null) + { + this.Encoding = (Encoding)other.Encoding.Clone(); + } + + this.Tag = other.Tag; + } + internal IptcValue(IptcTag tag, byte[] value) { Guard.NotNull(value, nameof(value)); @@ -74,6 +90,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// public int Length => this.data.Length; + /// + public IptcValue DeepClone() => new IptcValue(this); + /// /// Determines whether the specified object is equal to the current . /// diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs new file mode 100644 index 0000000000..045859c361 --- /dev/null +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -0,0 +1,88 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Linq; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Metadata.Profiles.Iptc; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC +{ + public class IptcProfileTests + { + private static JpegDecoder JpegDecoder => new JpegDecoder() { IgnoreMetadata = false }; + + [Theory] + [WithFile(TestImages.Jpeg.Baseline.Iptc, PixelTypes.Rgba32)] + public void ReadIptcProfile(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(JpegDecoder)) + { + Assert.NotNull(image.Metadata.IptcProfile); + IEnumerable iptcValues = image.Metadata.IptcProfile.Values; + ContainsIptcValue(iptcValues, IptcTag.Caption, "description"); + ContainsIptcValue(iptcValues, IptcTag.CaptionWriter, "description writer"); + ContainsIptcValue(iptcValues, IptcTag.Headline, "headline"); + ContainsIptcValue(iptcValues, IptcTag.SpecialInstructions, "special instructions"); + ContainsIptcValue(iptcValues, IptcTag.Byline, "author"); + ContainsIptcValue(iptcValues, IptcTag.BylineTitle, "author title"); + ContainsIptcValue(iptcValues, IptcTag.Credit, "credits"); + ContainsIptcValue(iptcValues, IptcTag.Source, "source"); + ContainsIptcValue(iptcValues, IptcTag.Title, "title"); + ContainsIptcValue(iptcValues, IptcTag.CreatedDate, "20200414"); + ContainsIptcValue(iptcValues, IptcTag.City, "city"); + ContainsIptcValue(iptcValues, IptcTag.SubLocation, "sublocation"); + ContainsIptcValue(iptcValues, IptcTag.ProvinceState, "province-state"); + ContainsIptcValue(iptcValues, IptcTag.Country, "country"); + ContainsIptcValue(iptcValues, IptcTag.Category, "category"); + ContainsIptcValue(iptcValues, IptcTag.Priority, "1"); + ContainsIptcValue(iptcValues, IptcTag.Keyword, "keywords"); + ContainsIptcValue(iptcValues, IptcTag.CopyrightNotice, "copyright"); + } + } + + [Fact] + public void IptcProfile_CloneIsDeep() + { + // arrange + var profile = new IptcProfile(); + var captionWriter = "unittest"; + var caption = "test"; + profile.SetValue(IptcTag.CaptionWriter, captionWriter); + profile.SetValue(IptcTag.Caption, caption); + + // act + IptcProfile clone = profile.DeepClone(); + clone.SetValue(IptcTag.Caption, "changed"); + + // assert + Assert.Equal(2, clone.Values.Count()); + ContainsIptcValue(clone.Values, IptcTag.CaptionWriter, captionWriter); + ContainsIptcValue(clone.Values, IptcTag.Caption, "changed"); + ContainsIptcValue(profile.Values, IptcTag.Caption, caption); + } + + [Fact] + public void IptcValue_CloneIsDeep() + { + // arrange + var iptcValue = new IptcValue(IptcTag.Caption, System.Text.Encoding.UTF8, "test"); + + // act + IptcValue clone = iptcValue.DeepClone(); + clone.Value = "changed"; + + // assert + Assert.NotEqual(iptcValue.Value, clone.Value); + } + + private static void ContainsIptcValue(IEnumerable values, IptcTag tag, string value) + { + Assert.True(values.Any(val => val.Tag == tag), $"Missing iptc tag {tag}"); + Assert.True(values.Contains(new IptcValue(tag, System.Text.Encoding.UTF8.GetBytes(value))), $"expected iptc value '{value}' was not found for tag '{tag}'"); + } + } +} diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 892568803e..d006c6682a 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -162,6 +162,7 @@ namespace SixLabors.ImageSharp.Tests public const string LowContrast = "Jpg/baseline/AsianCarvingLowContrast.jpg"; public const string Testorig12bit = "Jpg/baseline/testorig12.jpg"; public const string YcckSubsample1222 = "Jpg/baseline/ycck-subsample-1222.jpg"; + public const string Iptc = "Jpg/baseline/iptc.jpg"; public static readonly string[] All = { diff --git a/tests/Images/Input/Jpg/baseline/iptc.jpg b/tests/Images/Input/Jpg/baseline/iptc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de30930d6b1db7b7bc7239dfd3b4145d814afefb GIT binary patch literal 18611 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


{^xg;q*`?zA!sq*a7t};Y zC8_JqMAV7v9Cfs``$5FU-%D7JSjjJtyEhN~XGqPd2@P+(!i7OziT%sADJ2)0kCm>M zE?&Be`CE%m>RQs%<}Jzb32Sao8t?X4?RhgVWZ6B8z3m6Pta8!C`KxaugSWXnro760 zrFkRt2^l_r^*~YD5L^4A{M}w(IPN{k6d%1a_{zR-wlDe;i=UPJq@q}~WhwT1Dz+iq zV?@Y|4bi!?co*0B{&1L~&fqrvGMPJP|GE={PKC|fI6ty%#ARn$)@Qj)yY$Z{*VgBw zlWGie-SaTvZuhv&_RfaY3f{3` z$GWX?f=j>4s-8+cHV=gz*o|Mrc(i>!>+B( zp7}ENYWT*Vj#hu_x7BXLvDRGI>48TJb!Q(sk9?KNh#sFZ{$vrE?0sC3t6FeDL*7(Z zp0|?rwkoIqks~p;9*$wQ4!$>(|C8tkKmYZ0B?ouDLbh$5>SK7RZm!(4NVILQ?!gzc zJNzMB;gm`xhtR25v8bK<-sX^v-0CO6x62NqiQ6s1gNXPlgO zS$)DWW%z5a1eMvjZoIjf;&&zpXie|z|G(|51JTfIy4iw{xSAk6{A3H#wg0?*~Y zaH^&Uv6h4{;%(jEa{l_v{rSz5AtUqiH%a#mf=O6WOLJWMqo8?54%F-BILw&vEM?%+ zpC_OEcw~hm=f-5njHs5&w>POgp}SU9%u~ z8j|t#vBv}HS+lQMqsEF@zxn{$=!~67b$&yq50d$3y9O*vo-q5!N1jpFw%l+iPN>>E zIn>GP<%7~1^4szM-cwsoDSlmc^jKtrVB4E|^5fWZFS1B43oFNN4Euzd$vherfX!0P zKOMUE@~|+v&fW7?Sy<|bOPdeN`+reCs(!)#s^!_Tkl-wFtG{@aKin8Qx@0EP{?Uob znuYj6IJk-0B+w+n1)DyT2rZk+g0k>^HT&9e_EI1ysJvUuvGPaT#O${t0R51%Wy zp=}v^-?^lp8|UCt^1|JohgS3RHXn)}5axO=HDaPXIJKbi%bZEGo17jC3Tlh;`u#e2 zXZk9SM-^LHuMdB}bX3;iwMPe5&ELz>_^#MF_`DlOl@YN2hR5ZI%~=0iDOzU!y|bym m>o!KjjMOaqY^3T^|IBcYH%C>Kb7|A|j}mfJHSsswYX1*+AgjFq literal 0 HcmV?d00001 From ba883d7c8ad493188b3dc514dea176cfac380e6e Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 14 Apr 2020 18:27:42 +0200 Subject: [PATCH 119/213] Add support for writing IPTC metadata --- .../Formats/Jpeg/JpegEncoderCore.cs | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 32f4d22878..4791a04a0e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -4,6 +4,7 @@ using System; using System.Buffers.Binary; using System.IO; +using System.Linq; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -13,6 +14,7 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; +using SixLabors.ImageSharp.Metadata.Profiles.Iptc; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Jpeg @@ -647,9 +649,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// Writes the EXIF profile. ///
/// The exif profile. - /// - /// Thrown if the EXIF profile size exceeds the limit - /// private void WriteExifProfile(ExifProfile exifProfile) { if (exifProfile is null || exifProfile.Values.Count == 0) @@ -697,16 +696,56 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } } + /// + /// Writes the IPTC metadata. + /// + /// The iptc metadata to write. + private void WriteIptcProfile(IptcProfile iptcProfile) + { + if (iptcProfile is null || !iptcProfile.Values.Any()) + { + return; + } + + iptcProfile.UpdateData(); + var data = iptcProfile.Data; + if (data.Length == 0) + { + return; + } + + var app13length = data.Length + ProfileResolver.AdobeImageResourceBlockMarker.Length + ProfileResolver.AdobeIptcMarker.Length + 2 + 4; + this.WriteAppHeader(app13length, JpegConstants.Markers.APP13); + this.outputStream.Write(this.buffer, 0, 4); + this.outputStream.Write(ProfileResolver.AdobeImageResourceBlockMarker); + this.outputStream.Write(ProfileResolver.AdobeIptcMarker); + this.outputStream.WriteByte(0); // a null name consists of two bytes of 0. + this.outputStream.WriteByte(0); + BinaryPrimitives.WriteInt32BigEndian(this.buffer, data.Length); + this.outputStream.Write(this.buffer, 0, 4); + this.outputStream.Write(data, 0, data.Length); + } + /// /// Writes the App1 header. /// - /// The length of the data the app1 marker contains + /// The length of the data the app1 marker contains. private void WriteApp1Header(int app1Length) + { + this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1); + } + + /// + /// Writes a AppX header. + /// + /// The length of the data the app marker contains. + /// The app marker to write. + private void WriteAppHeader(int length, byte appMarker) { this.buffer[0] = JpegConstants.Markers.XFF; - this.buffer[1] = JpegConstants.Markers.APP1; // Application Marker - this.buffer[2] = (byte)((app1Length >> 8) & 0xFF); - this.buffer[3] = (byte)(app1Length & 0xFF); + this.buffer[1] = appMarker; + this.buffer[2] = (byte)((length >> 8) & 0xFF); + this.buffer[3] = (byte)(length & 0xFF); this.outputStream.Write(this.buffer, 0, 4); } @@ -805,6 +844,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg metadata.SyncProfiles(); this.WriteExifProfile(metadata.ExifProfile); this.WriteIccProfile(metadata.IccProfile); + this.WriteIptcProfile(metadata.IptcProfile); } ///
From 0e49478f37964d7603a069597ef4319ae3c49dbb Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 15 Apr 2020 15:00:25 +0200 Subject: [PATCH 120/213] Add tests for writing IPTC --- .../Formats/Jpeg/JpegDecoderCore.cs | 11 ++-- .../Formats/Jpeg/JpegEncoderCore.cs | 15 +++-- .../Profiles/IPTC/IptcProfileTests.cs | 60 ++++++++++++++++++- 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 46f0e694e0..023bbaac7e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -623,17 +623,16 @@ namespace SixLabors.ImageSharp.Formats.Jpeg return; } - var identifier = new byte[ProfileResolver.AdobePhotoshopApp13Marker.Length]; - this.InputStream.Read(identifier, 0, identifier.Length); - remaining -= identifier.Length; - if (ProfileResolver.IsProfile(identifier, ProfileResolver.AdobePhotoshopApp13Marker)) + this.InputStream.Read(this.temp, 0, ProfileResolver.AdobePhotoshopApp13Marker.Length); + remaining -= ProfileResolver.AdobePhotoshopApp13Marker.Length; + if (ProfileResolver.IsProfile(this.temp, ProfileResolver.AdobePhotoshopApp13Marker)) { var resourceBlockData = new byte[remaining]; this.InputStream.Read(resourceBlockData, 0, remaining); Span blockDataSpan = resourceBlockData.AsSpan(); - while (blockDataSpan.Length > 10) - { + while (blockDataSpan.Length > 12) + { if (!ProfileResolver.IsProfile(blockDataSpan.Slice(0, 4), ProfileResolver.AdobeImageResourceBlockMarker)) { return; diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 4791a04a0e..a3786ae1c2 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // Write the Start Of Image marker. this.WriteApplicationHeader(metadata); - // Write Exif and ICC profiles + // Write Exif, ICC and IPTC profiles this.WriteProfiles(metadata); // Write the quantization tables. @@ -708,18 +708,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } iptcProfile.UpdateData(); - var data = iptcProfile.Data; + byte[] data = iptcProfile.Data; if (data.Length == 0) { return; } - var app13length = data.Length + ProfileResolver.AdobeImageResourceBlockMarker.Length + ProfileResolver.AdobeIptcMarker.Length + 2 + 4; - this.WriteAppHeader(app13length, JpegConstants.Markers.APP13); - this.outputStream.Write(this.buffer, 0, 4); + var app13Length = 2 + ProfileResolver.AdobePhotoshopApp13Marker.Length + + ProfileResolver.AdobeImageResourceBlockMarker.Length + + ProfileResolver.AdobeIptcMarker.Length + + 2 + 4 + data.Length; + this.WriteAppHeader(app13Length, JpegConstants.Markers.APP13); + this.outputStream.Write(ProfileResolver.AdobePhotoshopApp13Marker); this.outputStream.Write(ProfileResolver.AdobeImageResourceBlockMarker); this.outputStream.Write(ProfileResolver.AdobeIptcMarker); - this.outputStream.WriteByte(0); // a null name consists of two bytes of 0. + this.outputStream.WriteByte(0); // a empty pascal string (padded to make size even) this.outputStream.WriteByte(0); BinaryPrimitives.WriteInt32BigEndian(this.buffer, data.Length); this.outputStream.Write(this.buffer, 0, 4); diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index 045859c361..40dd76836f 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Collections.Generic; +using System.IO; using System.Linq; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Metadata.Profiles.Iptc; @@ -16,13 +17,13 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC [Theory] [WithFile(TestImages.Jpeg.Baseline.Iptc, PixelTypes.Rgba32)] - public void ReadIptcProfile(TestImageProvider provider) + public void ReadIptcMetadata_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(JpegDecoder)) { Assert.NotNull(image.Metadata.IptcProfile); - IEnumerable iptcValues = image.Metadata.IptcProfile.Values; + var iptcValues = image.Metadata.IptcProfile.Values.ToList(); ContainsIptcValue(iptcValues, IptcTag.Caption, "description"); ContainsIptcValue(iptcValues, IptcTag.CaptionWriter, "description writer"); ContainsIptcValue(iptcValues, IptcTag.Headline, "headline"); @@ -44,6 +45,27 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC } } + [Fact] + public void IptcProfile_ToAndFromByteArray_Works() + { + // arrange + var profile = new IptcProfile(); + var expectedCaptionWriter = "unittest"; + var expectedCaption = "test"; + profile.SetValue(IptcTag.CaptionWriter, expectedCaptionWriter); + profile.SetValue(IptcTag.Caption, expectedCaption); + + // act + profile.UpdateData(); + byte[] profileBytes = profile.Data; + var profileFromBytes = new IptcProfile(profileBytes); + + // assert + var iptcValues = profileFromBytes.Values.ToList(); + ContainsIptcValue(iptcValues, IptcTag.CaptionWriter, expectedCaptionWriter); + ContainsIptcValue(iptcValues, IptcTag.Caption, expectedCaption); + } + [Fact] public void IptcProfile_CloneIsDeep() { @@ -79,10 +101,44 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC Assert.NotEqual(iptcValue.Value, clone.Value); } + [Fact] + public void WritingImage_PreservesIptcProfile() + { + // arrange + var image = new Image(1, 1); + image.Metadata.IptcProfile = new IptcProfile(); + var expectedCaptionWriter = "unittest"; + var expectedCaption = "test"; + image.Metadata.IptcProfile.SetValue(IptcTag.CaptionWriter, expectedCaptionWriter); + image.Metadata.IptcProfile.SetValue(IptcTag.Caption, expectedCaption); + + // act + Image reloadedImage = WriteAndReadJpeg(image); + + // assert + IptcProfile actual = reloadedImage.Metadata.IptcProfile; + Assert.NotNull(actual); + var iptcValues = actual.Values.ToList(); + ContainsIptcValue(iptcValues, IptcTag.CaptionWriter, expectedCaptionWriter); + ContainsIptcValue(iptcValues, IptcTag.Caption, expectedCaption); + } + private static void ContainsIptcValue(IEnumerable values, IptcTag tag, string value) { Assert.True(values.Any(val => val.Tag == tag), $"Missing iptc tag {tag}"); Assert.True(values.Contains(new IptcValue(tag, System.Text.Encoding.UTF8.GetBytes(value))), $"expected iptc value '{value}' was not found for tag '{tag}'"); } + + private static Image WriteAndReadJpeg(Image image) + { + using (var memStream = new MemoryStream()) + { + image.SaveAsJpeg(memStream); + image.Dispose(); + + memStream.Position = 0; + return Image.Load(memStream); + } + } } } From 07eda44d28cc29a6a7f756b79fce5aac6765efae Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 15 Apr 2020 15:00:46 +0200 Subject: [PATCH 121/213] Add IPTC specification --- .../Metadata/Profiles/IPTC/IIMV4.2_IPTC.pdf | Bin 0 -> 364258 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/ImageSharp/Metadata/Profiles/IPTC/IIMV4.2_IPTC.pdf diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IIMV4.2_IPTC.pdf b/src/ImageSharp/Metadata/Profiles/IPTC/IIMV4.2_IPTC.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b00355181c0ed5b4b4fbf4bf740e03ac7734c28a GIT binary patch literal 364258 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⋘Z|$@aAK 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

gN2y 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

gAovIisJGB5cD|12Fo2TW-dn*9nb98KsUI@!+3 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%0DjI&L-n~Gb+_*2x6Sr)Z8t=>H9ADStB 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%0DKr3c|_6 z%*4s$kD(?e?uHq))(9tnDZ;|i4#K=u-^>iKG=nhf3aId^prjE6%ZB$ivWH*n4$QXlo;B~ zTvSsA_FHq9e-LJ*lM_l52y}II<#FZbu}50~K_Vg|Kwdr|A0IcS2DhWTos)?hx1A%) z4xV)Gm z@$drw1(1r$zX!9m{UxLs{C6;vGur0+MVY~Y2pfbgM$R~5S_J(P4)qf~{?tuO0S1Ww zUjbp*_8S%d3gz|#>^t#)&_oQwaZ!v9hNZc?3`V3u`FQzwxp~3dAb~r)BBFf4q5=Y( zynLd(ykfw=)ck|4-*HG|Tskl!@dpkNn44D!gXRuMSQNxBDggQ!$4@o?g5w_p`G3@t z-v<5nx_`m*y#;&p9eaBls3aV1Z))NMP?v$Jm{=pw01yaZ-rj%)=-Q*req7Yg)&Go1 zMMYG`9`1b3CIuO&v$Lg{sEG)O&&1T6ms=2SD$ETQ;T7N(<_DQ@^TH7VCj4-?2){7@ zceH+nP8*O;9KsOSsATYy@J4s~GT)qCXlqukU2(WP|uiqvt)5wE4?5{L$NU zaUp7BVrKzicH=ffn437;I59&p<^TTpcUSo5*1q@luN^z@tl1wj=Kn#Lfq%jAoz}nT z$*)^I?+^TZ(%GZ`g6Euke`eVa!h9bE7!J#rxLBG2ByDUk!2$m-xc{EltrTXm`wPA@r}*amlegs@NbxS>IQ_yk+!DOxn|>W?I_oS05|h2_^#I z6MRcmDCU108e}fGubn7T2LF&r6Lv9+hV<22(;K7jWtgI-WY~yQPyp_Gysw4>p1k6T z)r?S)=^hQx7~&zV8qqh)7ZA`0mY&VN1-f8c~l$`dJ6|ae{_|xdP(}}}@s@mK~R|D^-6XzW6o;b95)A_=HW-Cd- z+iQ~7PD;G`RGJ-$3}G%8Q~j3Y-r%PC<$T2KwUcUx`M%abb!{+KZ*-SXg;(;zKud){ zLoN7q(%|Kx0HQMG0V)Cpcq^RCEG(dqngGcDwUdM0{i4sRvk29!xI6V>vW6xu2g?%a z=q^4fr#!|^prwG;ja^;khB@{Wmc}Yi= z!P5n88~^rkjT_iCd)RGSHm`bO`)G$3pUJIo+}@_TdE#wr`S?XwKp8|Uey2=Y8FKTB z{hrG)cguw}DwV=tlItg1^dHJobrZC$qnOyarq$Wj&JiF0R7WGsEa8|%4FJRkh5kz4 zsvu(^29p%v2ZQ+qVAA|DAVDxlSXNMkA1nj|Vbt1^AeazTOhi_S4=ltdAS?-k!34pQ zQv5J}X=z?zUTGC#sb*#rvcsH%kvh!Y6nDvW&b#OJYn#QF zk8_N-zJ547+fRzGJEMR^EKeLcv&*tyY+5|3G~Z>*I=>AWZFu@{9AIX{O>lH zy=iWg?Z_3)7ocJ8@?T@jsY~tlX>Gi|){YR=b5TxCB}n$X%HQYOsCpSq(0$k7-MxiA zJMFbtY3Iq}sb!Cd+Nq6iRqxO~UFbaaX=iSBrJ__q&Vdo5;+5FA%;XB#e!(UWv^Hg? zl%B1ewx69`;ypQI^!dG?g13Z+QsnOf|5@UpD+^Dx$xB)Qj?deXnU@RLA0_*Gzxr6k>n5a;82bztYMzY4|Ms z7VRsXn`?U|FT7Hl)U0o(>pNK&$!VG|7;L^+tr_u+8lSCIR-?QHq^v4&OTq*bD6HWU z%_?+dUo8hpuo`?)MNBXh-9a?&M~Y5&2wNdi)V`6Af9}Oj8s+I(k-ka-|XUWRoo_bsQxmoDo{K<2ibo)e}I;P)U0A$ zFb~#7dDaBe@@KxS-99O*xpz3jY;}6XaAGbNrD^;z{b=mnS>NY Date: Wed, 15 Apr 2020 18:07:18 +0200 Subject: [PATCH 122/213] Add padding byte when resource name length is odd --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 023bbaac7e..896f41aaed 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -668,6 +668,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { byte nameLength = blockDataSpan[2]; var nameDataSize = nameLength == 0 ? 2 : nameLength; + if (nameDataSize % 2 != 0) + { + nameDataSize++; + } + return nameDataSize; } From ed1a0631f0c83ae375865b63c0cfebe2238abe09 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 15 Apr 2020 18:26:40 +0200 Subject: [PATCH 123/213] Add testcase for app13 marker with empty IPTC --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 9 ++++++--- .../Metadata/Profiles/IPTC/IptcProfileTests.cs | 9 +++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + .../Jpg/baseline/iptc-psAPP13-wIPTCempty.jpg | Bin 0 -> 18329 bytes 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 tests/Images/Input/Jpg/baseline/iptc-psAPP13-wIPTCempty.jpg diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 896f41aaed..93cdd18c31 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -644,9 +644,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { var resourceBlockNameLength = ReadImageResourceNameLength(blockDataSpan); var resourceDataSize = ReadResourceDataLength(blockDataSpan, resourceBlockNameLength); - this.isIptc = true; - this.iptcData = blockDataSpan.Slice(2 + resourceBlockNameLength + 4, resourceDataSize).ToArray(); - break; + if (resourceDataSize > 0) + { + this.isIptc = true; + this.iptcData = blockDataSpan.Slice(2 + resourceBlockNameLength + 4, resourceDataSize).ToArray(); + break; + } } else { diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index 40dd76836f..914690102a 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -45,6 +45,15 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC } } + [Theory] + [WithFile(TestImages.Jpeg.Baseline.App13WithEmptyIptc, PixelTypes.Rgba32)] + public void ReadApp13_WithEmptyIptc_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder); + Assert.Null(image.Metadata.IptcProfile); + } + [Fact] public void IptcProfile_ToAndFromByteArray_Works() { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d006c6682a..65d9752573 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -163,6 +163,7 @@ namespace SixLabors.ImageSharp.Tests public const string Testorig12bit = "Jpg/baseline/testorig12.jpg"; public const string YcckSubsample1222 = "Jpg/baseline/ycck-subsample-1222.jpg"; public const string Iptc = "Jpg/baseline/iptc.jpg"; + public const string App13WithEmptyIptc = "Jpg/baseline/iptc-psAPP13-wIPTCempty.jpg"; public static readonly string[] All = { diff --git a/tests/Images/Input/Jpg/baseline/iptc-psAPP13-wIPTCempty.jpg b/tests/Images/Input/Jpg/baseline/iptc-psAPP13-wIPTCempty.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d60013dcd990b5cf53d842d94e2d15f2a296c288 GIT binary patch literal 18329 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 Date: Wed, 15 Apr 2020 20:37:11 +0200 Subject: [PATCH 124/213] Some IPTC tags can now be added multiple times, some are restricted from doing so --- .../Metadata/Profiles/IPTC/IptcProfile.cs | 61 +++++++++- .../Metadata/Profiles/IPTC/IptcTag.cs | 107 +++++++++--------- .../Profiles/IPTC/IptcProfileTests.cs | 89 ++++++++++++++- 3 files changed, 197 insertions(+), 60 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index 57704949c0..119c6f2b50 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -34,6 +34,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc public IptcProfile(byte[] data) { this.Data = data; + this.Initialize(); } private IptcProfile(IptcProfile other) @@ -99,7 +100,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// Removes the value with the specified tag. ///

/// The tag of the iptc value. - /// True when the value was fount and removed. + /// True when the value was found and removed. public bool RemoveValue(IptcTag tag) { this.Initialize(); @@ -140,13 +141,16 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { Guard.NotNull(encoding, nameof(encoding)); - foreach (IptcValue iptcValue in this.Values) + if (!this.IsRepeatable(tag)) { - if (iptcValue.Tag == tag) + foreach (IptcValue iptcValue in this.Values) { - iptcValue.Encoding = encoding; - iptcValue.Value = value; - return; + if (iptcValue.Tag == tag) + { + iptcValue.Encoding = encoding; + iptcValue.Value = value; + return; + } } } @@ -228,5 +232,50 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc i += count; } } + + private bool IsRepeatable(IptcTag tag) + { + switch (tag) + { + case IptcTag.RecordVersion: + case IptcTag.ObjectType: + case IptcTag.Name: + case IptcTag.EditStatus: + case IptcTag.EditorialUpdate: + case IptcTag.Urgency: + case IptcTag.Category: + case IptcTag.FixtureIdentifier: + case IptcTag.ReleaseDate: + case IptcTag.ReleaseTime: + case IptcTag.ExpirationDate: + case IptcTag.ExpirationTime: + case IptcTag.SpecialInstructions: + case IptcTag.ActionAdvised: + case IptcTag.CreatedDate: + case IptcTag.CreatedTime: + case IptcTag.DigitalCreationDate: + case IptcTag.DigitalCreationTime: + case IptcTag.OriginatingProgram: + case IptcTag.ProgramVersion: + case IptcTag.ObjectCycle: + case IptcTag.City: + case IptcTag.SubLocation: + case IptcTag.ProvinceState: + case IptcTag.CountryCode: + case IptcTag.Country: + case IptcTag.OriginalTransmissionReference: + case IptcTag.Headline: + case IptcTag.Credit: + case IptcTag.Source: + case IptcTag.CopyrightNotice: + case IptcTag.Caption: + case IptcTag.ImageType: + case IptcTag.ImageOrientation: + return false; + + default: + return true; + } + } } } diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs index 3e6da0e092..cd0b620720 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs @@ -9,242 +9,247 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc public enum IptcTag { /// - /// Unknown + /// Unknown. /// Unknown = -1, /// - /// Record version + /// Record version, not repeatable. /// RecordVersion = 0, /// - /// Object type + /// Object type, not repeatable. /// ObjectType = 3, /// - /// Object attribute + /// Object attribute. /// ObjectAttribute = 4, /// - /// Title + /// Object Name, not repeatable. /// - Title = 5, + Name = 5, /// - /// Edit status + /// Edit status, not repeatable. /// EditStatus = 7, /// - /// Editorial update + /// Editorial update, not repeatable. /// EditorialUpdate = 8, /// - /// Priority + /// Urgency, not repeatable. /// - Priority = 10, + Urgency = 10, /// - /// Category + /// Subject Reference. + /// + SubjectReference = 12, + + /// + /// Category, not repeatable. /// Category = 15, /// - /// Supplemental categories + /// Supplemental categories. /// SupplementalCategories = 20, /// - /// Fixture identifier + /// Fixture identifier, not repeatable. /// FixtureIdentifier = 22, /// - /// Keyword + /// Keywords. /// - Keyword = 25, + Keywords = 25, /// - /// Location code + /// Location code. /// LocationCode = 26, /// - /// Location name + /// Location name. /// LocationName = 27, /// - /// Release date + /// Release date, not repeatable. /// ReleaseDate = 30, /// - /// Release time + /// Release time, not repeatable. /// ReleaseTime = 35, /// - /// Expiration date + /// Expiration date, not repeatable. /// ExpirationDate = 37, /// - /// Expiration time + /// Expiration time, not repeatable. /// ExpirationTime = 38, /// - /// Special instructions + /// Special instructions, not repeatable. /// SpecialInstructions = 40, /// - /// Action advised + /// Action advised, not repeatable. /// ActionAdvised = 42, /// - /// Reference service + /// Reference service. /// ReferenceService = 45, /// - /// Reference date + /// Reference date. /// ReferenceDate = 47, /// - /// ReferenceNumber + /// ReferenceNumber. /// ReferenceNumber = 50, /// - /// Created date + /// Created date, not repeatable. /// CreatedDate = 55, /// - /// Created time + /// Created time, not repeatable. /// CreatedTime = 60, /// - /// Digital creation date + /// Digital creation date, not repeatable. /// DigitalCreationDate = 62, /// - /// Digital creation time + /// Digital creation time, not repeatable. /// DigitalCreationTime = 63, /// - /// Originating program + /// Originating program, not repeatable. /// OriginatingProgram = 65, /// - /// Program version + /// Program version, not repeatable. /// ProgramVersion = 70, /// - /// Object cycle + /// Object cycle, not repeatable. /// ObjectCycle = 75, /// - /// Byline + /// Byline. /// Byline = 80, /// - /// Byline title + /// Byline title. /// BylineTitle = 85, /// - /// City + /// City, not repeatable. /// City = 90, /// - /// Sub location + /// Sub location, not repeatable. /// SubLocation = 92, /// - /// Province/State + /// Province/State, not repeatable. /// ProvinceState = 95, /// - /// Country code + /// Country code, not repeatable. /// CountryCode = 100, /// - /// Country + /// Country, not repeatable. /// Country = 101, /// - /// Original transmission reference + /// Original transmission reference, not repeatable. /// OriginalTransmissionReference = 103, /// - /// Headline + /// Headline, not repeatable. /// Headline = 105, /// - /// Credit + /// Credit, not repeatable. /// Credit = 110, /// - /// Source + /// Source, not repeatable. /// Source = 115, /// - /// Copyright notice + /// Copyright notice, not repeatable. /// CopyrightNotice = 116, /// - /// Contact + /// Contact. /// Contact = 118, /// - /// Caption + /// Caption, not repeatable. /// Caption = 120, /// - /// Local caption + /// Local caption. /// LocalCaption = 121, /// - /// Caption writer + /// Caption writer. /// CaptionWriter = 122, /// - /// Image type + /// Image type, not repeatable. /// ImageType = 130, /// - /// Image orientation + /// Image orientation, not repeatable. /// ImageOrientation = 131, diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index 914690102a..f15a0992d2 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -32,15 +32,15 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC ContainsIptcValue(iptcValues, IptcTag.BylineTitle, "author title"); ContainsIptcValue(iptcValues, IptcTag.Credit, "credits"); ContainsIptcValue(iptcValues, IptcTag.Source, "source"); - ContainsIptcValue(iptcValues, IptcTag.Title, "title"); + ContainsIptcValue(iptcValues, IptcTag.Name, "title"); ContainsIptcValue(iptcValues, IptcTag.CreatedDate, "20200414"); ContainsIptcValue(iptcValues, IptcTag.City, "city"); ContainsIptcValue(iptcValues, IptcTag.SubLocation, "sublocation"); ContainsIptcValue(iptcValues, IptcTag.ProvinceState, "province-state"); ContainsIptcValue(iptcValues, IptcTag.Country, "country"); ContainsIptcValue(iptcValues, IptcTag.Category, "category"); - ContainsIptcValue(iptcValues, IptcTag.Priority, "1"); - ContainsIptcValue(iptcValues, IptcTag.Keyword, "keywords"); + ContainsIptcValue(iptcValues, IptcTag.Urgency, "1"); + ContainsIptcValue(iptcValues, IptcTag.Keywords, "keywords"); ContainsIptcValue(iptcValues, IptcTag.CopyrightNotice, "copyright"); } } @@ -132,6 +132,89 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC ContainsIptcValue(iptcValues, IptcTag.Caption, expectedCaption); } + [Theory] + [InlineData(IptcTag.ObjectAttribute)] + [InlineData(IptcTag.SubjectReference)] + [InlineData(IptcTag.SupplementalCategories)] + [InlineData(IptcTag.Keywords)] + [InlineData(IptcTag.LocationCode)] + [InlineData(IptcTag.LocationName)] + [InlineData(IptcTag.ReferenceService)] + [InlineData(IptcTag.ReferenceDate)] + [InlineData(IptcTag.ReferenceNumber)] + [InlineData(IptcTag.Byline)] + [InlineData(IptcTag.BylineTitle)] + [InlineData(IptcTag.Contact)] + [InlineData(IptcTag.LocalCaption)] + [InlineData(IptcTag.CaptionWriter)] + public void IptcProfile_AddRepeatable_Works(IptcTag tag) + { + // arrange + var profile = new IptcProfile(); + var expectedValue1 = "test"; + var expectedValue2 = "another one"; + profile.SetValue(tag, expectedValue1); + + // act + profile.SetValue(tag, expectedValue2); + + // assert + var values = profile.Values.ToList(); + Assert.Equal(2, values.Count); + ContainsIptcValue(values, tag, expectedValue1); + ContainsIptcValue(values, tag, expectedValue2); + } + + [Theory] + [InlineData(IptcTag.RecordVersion)] + [InlineData(IptcTag.ObjectType)] + [InlineData(IptcTag.Name)] + [InlineData(IptcTag.EditStatus)] + [InlineData(IptcTag.EditorialUpdate)] + [InlineData(IptcTag.Urgency)] + [InlineData(IptcTag.Category)] + [InlineData(IptcTag.FixtureIdentifier)] + [InlineData(IptcTag.ReleaseDate)] + [InlineData(IptcTag.ReleaseTime)] + [InlineData(IptcTag.ExpirationDate)] + [InlineData(IptcTag.ExpirationTime)] + [InlineData(IptcTag.SpecialInstructions)] + [InlineData(IptcTag.ActionAdvised)] + [InlineData(IptcTag.CreatedDate)] + [InlineData(IptcTag.CreatedTime)] + [InlineData(IptcTag.DigitalCreationDate)] + [InlineData(IptcTag.DigitalCreationTime)] + [InlineData(IptcTag.OriginatingProgram)] + [InlineData(IptcTag.ProgramVersion)] + [InlineData(IptcTag.ObjectCycle)] + [InlineData(IptcTag.City)] + [InlineData(IptcTag.SubLocation)] + [InlineData(IptcTag.ProvinceState)] + [InlineData(IptcTag.CountryCode)] + [InlineData(IptcTag.Country)] + [InlineData(IptcTag.OriginalTransmissionReference)] + [InlineData(IptcTag.Headline)] + [InlineData(IptcTag.Credit)] + [InlineData(IptcTag.CopyrightNotice)] + [InlineData(IptcTag.Caption)] + [InlineData(IptcTag.ImageType)] + [InlineData(IptcTag.ImageOrientation)] + public void IptcProfile_AddNoneRepeatable_DoesOverrideOldValue(IptcTag tag) + { + // arrange + var profile = new IptcProfile(); + var expectedValue = "another one"; + profile.SetValue(tag, "test"); + + // act + profile.SetValue(tag, expectedValue); + + // assert + var values = profile.Values.ToList(); + Assert.Equal(1, values.Count); + ContainsIptcValue(values, tag, expectedValue); + } + private static void ContainsIptcValue(IEnumerable values, IptcTag tag, string value) { Assert.True(values.Any(val => val.Tag == tag), $"Missing iptc tag {tag}"); From 86462e55138f407cdd592096a7e5e7bb9ceec327 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 16 Apr 2020 11:35:29 +0200 Subject: [PATCH 125/213] Throw if IPTC data exceeds limit --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 14 +++++++++++--- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 9 +++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 93cdd18c31..4000fa0f62 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -644,10 +644,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { var resourceBlockNameLength = ReadImageResourceNameLength(blockDataSpan); var resourceDataSize = ReadResourceDataLength(blockDataSpan, resourceBlockNameLength); - if (resourceDataSize > 0) + int dataStartIdx = 2 + resourceBlockNameLength + 4; + if (resourceDataSize > 0 && blockDataSpan.Length >= dataStartIdx + resourceDataSize) { this.isIptc = true; - this.iptcData = blockDataSpan.Slice(2 + resourceBlockNameLength + 4, resourceDataSize).ToArray(); + this.iptcData = blockDataSpan.Slice(dataStartIdx, resourceDataSize).ToArray(); break; } } @@ -655,7 +656,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { var resourceBlockNameLength = ReadImageResourceNameLength(blockDataSpan); var resourceDataSize = ReadResourceDataLength(blockDataSpan, resourceBlockNameLength); - blockDataSpan = blockDataSpan.Slice(2 + resourceBlockNameLength + 4 + resourceDataSize); + int dataStartIdx = 2 + resourceBlockNameLength + 4; + if (blockDataSpan.Length < dataStartIdx + resourceDataSize) + { + // Not enough data or the resource data size is wrong. + break; + } + + blockDataSpan = blockDataSpan.Slice(dataStartIdx + resourceDataSize); } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index a3786ae1c2..eed95c6b07 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -700,8 +700,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// Writes the IPTC metadata. ///
/// Applies Bradley Adaptive Threshold to the image. @@ -62,11 +55,9 @@ namespace SixLabors.ImageSharp.Processing /// Upper (white) color for thresholding. /// Lower (black) color for thresholding /// Rectangle region to apply the processor on. - /// The pixel format. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower), rectangle); + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower, Rectangle rectangle) + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower), rectangle); /// /// Applies Bradley Adaptive Threshold to the image. @@ -76,10 +67,8 @@ namespace SixLabors.ImageSharp.Processing /// Lower (black) color for thresholding /// Threshold limit (0.0-1.0) to consider for binarization. /// Rectangle region to apply the processor on. - /// The pixel format. /// The . - public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, float thresholdLimit, Rectangle rectangle) - where TPixel : struct, IPixel - => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, thresholdLimit), rectangle); + public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower, float thresholdLimit, Rectangle rectangle) + => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower, thresholdLimit), rectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 2ad170e380..3558a94899 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -1,160 +1,77 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Buffers; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; -using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Binarization { /// - /// Performs Bradley Adaptive Threshold filter against an image + /// Performs Bradley Adaptive Threshold filter against an image. /// - /// The pixel format of the image - internal class AdaptiveThresholdProcessor : ImageProcessor - where TPixel : struct, IPixel + /// + /// Implements "Adaptive Thresholding Using the Integral Image", + /// see paper: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.420.7883&rep=rep1&type=pdf + /// + public class AdaptiveThresholdProcessor : IImageProcessor { - private readonly PixelOperations pixelOpInstance; - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public AdaptiveThresholdProcessor() - : this(NamedColors.White, NamedColors.Black, 0.85f) + : this(Color.White, Color.Black, 0.85f) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Threshold limit + /// Threshold limit. public AdaptiveThresholdProcessor(float thresholdLimit) - : this(NamedColors.White, NamedColors.Black, thresholdLimit) + : this(Color.White, Color.Black, thresholdLimit) { } - public AdaptiveThresholdProcessor(TPixel upper, TPixel lower) + /// + /// Initializes a new instance of the class. + /// + /// Color for upper threshold. + /// Color for lower threshold. + public AdaptiveThresholdProcessor(Color upper, Color lower) : this(upper, lower, 0.85f) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Color for upper threshold - /// Color for lower threshold - /// Threshold limit - public AdaptiveThresholdProcessor(TPixel upper, TPixel lower, float thresholdLimit) + /// Color for upper threshold. + /// Color for lower threshold. + /// Threshold limit. + public AdaptiveThresholdProcessor(Color upper, Color lower, float thresholdLimit) { - this.pixelOpInstance = PixelOperations.Instance; - this.Upper = upper; this.Lower = lower; this.ThresholdLimit = thresholdLimit; } /// - /// Gets or sets upper color limit for thresholding + /// Gets or sets upper color limit for thresholding. /// - public TPixel Upper { get; set; } + public Color Upper { get; set; } /// - /// Gets or sets lower color limit for threshold + /// Gets or sets lower color limit for threshold. /// - public TPixel Lower { get; set; } + public Color Lower { get; set; } /// - /// Gets or sets the value for threshold limit + /// Gets or sets the value for threshold limit. /// public float ThresholdLimit { get; set; } - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - Rectangle intersect = Rectangle.Intersect(sourceRectangle, source.Bounds()); - - // Used ushort because the values should never exceed max ushort value - ushort startY = (ushort)intersect.Y; - ushort endY = (ushort)intersect.Bottom; - ushort startX = (ushort)intersect.X; - ushort endX = (ushort)intersect.Right; - - ushort width = (ushort)intersect.Width; - ushort height = (ushort)intersect.Height; - - // ClusterSize defines the size of cluster to used to check for average. Tweaked to support upto 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1' - byte clusterSize = (byte)Math.Truncate((width / 16f) - 1); - - // Using pooled 2d buffer for integer image table and temp memory to hold Rgb24 converted pixel data - using (Buffer2D intImage = configuration.MemoryAllocator.Allocate2D(width, height)) - using (IMemoryOwner tmpBuffer = configuration.MemoryAllocator.Allocate(width * height)) - { - // Defines the rectangle section of the image to work on - Rectangle workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); - - this.pixelOpInstance.ToRgb24(source.GetPixelSpan(), tmpBuffer.GetSpan()); - - for (ushort x = startX; x < endX; x++) - { - Span rgbSpan = tmpBuffer.GetSpan(); - ulong sum = 0; - for (ushort y = startY; y < endY; y++) - { - ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; - - sum += (ulong)(rgb.R + rgb.G + rgb.G); - if (x - startX != 0) - { - intImage[x - startX, y - startY] = intImage[x - startX - 1, y - startY] + sum; - } - else - { - intImage[x - startX, y - startY] = sum; - } - } - } - - ParallelHelper.IterateRows( - workingRectangle, - configuration, - rows => - { - Span rgbSpan = tmpBuffer.GetSpan(); - ushort x1, y1, x2, y2; - uint count = 0; - long sum = 0; - - for (ushort x = startX; x < endX; x++) - { - for (ushort y = (ushort)rows.Min; y < (ushort)rows.Max; y++) - { - ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; - - x1 = (ushort)Math.Max(x - startX - clusterSize + 1, 0); - x2 = (ushort)Math.Min(x - startX + clusterSize + 1, width - 1); - y1 = (ushort)Math.Max(y - startY - clusterSize + 1, 0); - y2 = (ushort)Math.Min(y - startY + clusterSize + 1, height - 1); - - count = (uint)((x2 - x1) * (y2 - y1)); - sum = (long)Math.Min(intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1], long.MaxValue); - - if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.ThresholdLimit) - { - source[x, y] = this.Lower; - } - else - { - source[x, y] = this.Upper; - } - } - } - }); - } - } + /// + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + where TPixel : unmanaged, IPixel + => new AdaptiveThresholdProcessor(configuration, this, source, sourceRectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs new file mode 100644 index 0000000000..130fc40f3f --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs @@ -0,0 +1,168 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Runtime.CompilerServices; + +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Binarization +{ + /// + /// Performs Bradley Adaptive Threshold filter against an image. + /// + internal class AdaptiveThresholdProcessor : ImageProcessor + where TPixel : unmanaged, IPixel + { + private readonly AdaptiveThresholdProcessor definition; + private readonly PixelOperations pixelOpInstance; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration which allows altering default behaviour or extending the library. + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public AdaptiveThresholdProcessor(Configuration configuration, AdaptiveThresholdProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) + { + this.pixelOpInstance = PixelOperations.Instance; + this.definition = definition; + } + + /// + protected override void OnFrameApply(ImageFrame source) + { + var intersect = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); + + Configuration configuration = this.Configuration; + TPixel upper = this.definition.Upper.ToPixel(); + TPixel lower = this.definition.Lower.ToPixel(); + float thresholdLimit = this.definition.ThresholdLimit; + + // Used ushort because the values should never exceed max ushort value. + ushort startY = (ushort)intersect.Y; + ushort endY = (ushort)intersect.Bottom; + ushort startX = (ushort)intersect.X; + ushort endX = (ushort)intersect.Right; + + ushort width = (ushort)intersect.Width; + ushort height = (ushort)intersect.Height; + + // ClusterSize defines the size of cluster to used to check for average. Tweaked to support up to 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1' + byte clusterSize = (byte)Math.Truncate((width / 16f) - 1); + + // Using pooled 2d buffer for integer image table and temp memory to hold Rgb24 converted pixel data. + using (Buffer2D intImage = this.Configuration.MemoryAllocator.Allocate2D(width, height)) + using (IMemoryOwner tmpBuffer = this.Configuration.MemoryAllocator.Allocate(width * height)) + { + // Defines the rectangle section of the image to work on. + var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); + + this.pixelOpInstance.ToRgb24(this.Configuration, source.GetPixelSpan(), tmpBuffer.GetSpan()); + + for (ushort x = startX; x < endX; x++) + { + Span rgbSpan = tmpBuffer.GetSpan(); + ulong sum = 0; + for (ushort y = startY; y < endY; y++) + { + ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; + + sum += (ulong)(rgb.R + rgb.G + rgb.G); + if (x - startX != 0) + { + intImage[x - startX, y - startY] = intImage[x - startX - 1, y - startY] + sum; + } + else + { + intImage[x - startX, y - startY] = sum; + } + } + } + + var operation = new RowOperation(workingRectangle, source, tmpBuffer, intImage, upper, lower, thresholdLimit, clusterSize, startX, endX, startY); + ParallelRowIterator.IterateRows( + configuration, + workingRectangle, + in operation); + } + } + + private readonly struct RowOperation : IRowOperation + { + private readonly Rectangle bounds; + private readonly ImageFrame source; + private readonly IMemoryOwner tmpBuffer; + private readonly Buffer2D intImage; + private readonly TPixel upper; + private readonly TPixel lower; + private readonly float thresholdLimit; + private readonly ushort startX; + private readonly ushort endX; + private readonly ushort startY; + private readonly byte clusterSize; + + [MethodImpl(InliningOptions.ShortMethod)] + public RowOperation( + Rectangle bounds, + ImageFrame source, + IMemoryOwner tmpBuffer, + Buffer2D intImage, + TPixel upper, + TPixel lower, + float thresholdLimit, + byte clusterSize, + ushort startX, + ushort endX, + ushort startY) + { + this.bounds = bounds; + this.source = source; + this.tmpBuffer = tmpBuffer; + this.intImage = intImage; + this.upper = upper; + this.lower = lower; + this.thresholdLimit = thresholdLimit; + this.startX = startX; + this.endX = endX; + this.startY = startY; + this.clusterSize = clusterSize; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void Invoke(int y) + { + Span rgbSpan = this.tmpBuffer.GetSpan(); + ushort x1, y1, x2, y2; + + for (ushort x = this.startX; x < this.endX; x++) + { + ref Rgb24 rgb = ref rgbSpan[(this.bounds.Width * y) + x]; + + x1 = (ushort)Math.Max(x - this.startX - this.clusterSize + 1, 0); + x2 = (ushort)Math.Min(x - this.startX + this.clusterSize + 1, this.bounds.Width - 1); + y1 = (ushort)Math.Max(y - this.startY - this.clusterSize + 1, 0); + y2 = (ushort)Math.Min(y - this.startY + this.clusterSize + 1, this.bounds.Height - 1); + + var count = (uint)((x2 - x1) * (y2 - y1)); + var sum = (long)Math.Min(this.intImage[x2, y2] - this.intImage[x1, y2] - this.intImage[x2, y1] + this.intImage[x1, y1], long.MaxValue); + + if ((rgb.R + rgb.G + rgb.B) * count <= sum * this.thresholdLimit) + { + this.source[x, y] = this.lower; + } + else + { + this.source[x, y] = this.upper; + } + } + } + } + } +} From 69639450979861eff73bc7cc17963f4e79a8f8fa Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 2 Apr 2020 15:18:53 +0200 Subject: [PATCH 095/213] Add tests for the AdaptiveThreshold processor --- .../Binarization/AdaptiveThresholdTests.cs | 77 ++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 3 + tests/Images/External | 2 +- tests/Images/Input/Png/Bradley01.png | Bin 0 -> 25266 bytes tests/Images/Input/Png/Bradley02.png | Bin 0 -> 26467 bytes 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs create mode 100644 tests/Images/Input/Png/Bradley01.png create mode 100644 tests/Images/Input/Png/Bradley02.png diff --git a/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs b/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs new file mode 100644 index 0000000000..309716eb55 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs @@ -0,0 +1,77 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Tga; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Binarization; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Binarization +{ + public class AdaptiveThresholdTests : BaseImageOperationsExtensionTest + { + [Fact] + public void AdaptiveThreshold_UsesDefaults_Works() + { + var expectedThresholdLimit = .85f; + Color expectedUpper = Color.White; + Color expectedLower = Color.Black; + this.operations.AdaptiveThreshold(); + AdaptiveThresholdProcessor p = this.Verify(); + Assert.Equal(expectedThresholdLimit, p.ThresholdLimit); + Assert.Equal(expectedUpper, p.Upper); + Assert.Equal(expectedLower, p.Lower); + } + + [Fact] + public void AdaptiveThreshold_SettingThresholdLimit_Works() + { + var expectedThresholdLimit = .65f; + this.operations.AdaptiveThreshold(expectedThresholdLimit); + AdaptiveThresholdProcessor p = this.Verify(); + Assert.Equal(expectedThresholdLimit, p.ThresholdLimit); + Assert.Equal(Color.White, p.Upper); + Assert.Equal(Color.Black, p.Lower); + } + + [Fact] + public void AdaptiveThreshold_SettingUpperLowerThresholds_Works() + { + Color expectedUpper = Color.HotPink; + Color expectedLower = Color.Yellow; + this.operations.AdaptiveThreshold(expectedUpper, expectedLower); + AdaptiveThresholdProcessor p = this.Verify(); + Assert.Equal(expectedUpper, p.Upper); + Assert.Equal(expectedLower, p.Lower); + } + + [Fact] + public void AdaptiveThreshold_SettingUpperLowerWithThresholdLimit_Works() + { + var expectedThresholdLimit = .77f; + Color expectedUpper = Color.HotPink; + Color expectedLower = Color.Yellow; + this.operations.AdaptiveThreshold(expectedUpper, expectedLower, expectedThresholdLimit); + AdaptiveThresholdProcessor p = this.Verify(); + Assert.Equal(expectedThresholdLimit, p.ThresholdLimit); + Assert.Equal(expectedUpper, p.Upper); + Assert.Equal(expectedLower, p.Lower); + } + + [Theory] + [WithFile(TestImages.Png.Bradley01, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.Bradley02, PixelTypes.Rgba32)] + public void AdaptiveThreshold_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage()) + { + image.Mutate(img => img.AdaptiveThreshold()); + image.DebugSave(provider); + image.CompareToReferenceOutput(ImageComparer.Exact, provider); + } + } + } +} diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 272998a896..e475a7712f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -83,6 +83,9 @@ namespace SixLabors.ImageSharp.Tests public const string Ducky = "Png/ducky.png"; public const string Rainbow = "Png/rainbow.png"; + public const string Bradley01 = "Png/Bradley01.png"; + public const string Bradley02 = "Png/Bradley02.png"; + // Issue 1014: https://github.com/SixLabors/ImageSharp/issues/1014 public const string Issue1014_1 = "Png/issues/Issue_1014_1.png"; public const string Issue1014_2 = "Png/issues/Issue_1014_2.png"; diff --git a/tests/Images/External b/tests/Images/External index fe694a3938..c04c8b73a9 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit fe694a3938bea3565071a96cb1c90c4cbc586ff9 +Subproject commit c04c8b73a99c1b198597ae640394d91ddd8e033b diff --git a/tests/Images/Input/Png/Bradley01.png b/tests/Images/Input/Png/Bradley01.png new file mode 100644 index 0000000000000000000000000000000000000000..b8c3c0b6f61c2f8126cf87402abdee1aa90d1a96 GIT binary patch literal 25266 zcmV({K+?a7P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 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 lUbL#erNrK`Tm;&!d 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 JPDHLkV1h5aoCyE` literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/Bradley02.png b/tests/Images/Input/Png/Bradley02.png new file mode 100644 index 0000000000000000000000000000000000000000..8aea767ab89b1d4f8f32a7f8f834d70ac63136ff GIT binary patch literal 26467 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 O0000eB literal 0 HcmV?d00001 From 75ac0eeb170ea6cb7be598cea853b807e89dc857 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 2 Apr 2020 17:25:46 +0200 Subject: [PATCH 096/213] Remove not needed tmp buffer --- .../AdaptiveThresholdProcessor{TPixel}.cs | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs index 130fc40f3f..109631ab8b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs @@ -2,8 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; @@ -58,20 +58,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Using pooled 2d buffer for integer image table and temp memory to hold Rgb24 converted pixel data. using (Buffer2D intImage = this.Configuration.MemoryAllocator.Allocate2D(width, height)) - using (IMemoryOwner tmpBuffer = this.Configuration.MemoryAllocator.Allocate(width * height)) { // Defines the rectangle section of the image to work on. var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); - this.pixelOpInstance.ToRgb24(this.Configuration, source.GetPixelSpan(), tmpBuffer.GetSpan()); - + Rgba32 rgb = default; for (ushort x = startX; x < endX; x++) { - Span rgbSpan = tmpBuffer.GetSpan(); ulong sum = 0; for (ushort y = startY; y < endY; y++) { - ref Rgb24 rgb = ref rgbSpan[(width * y) + x]; + Span row = source.GetPixelRowSpan(y); + ref TPixel rowRef = ref MemoryMarshal.GetReference(row); + ref TPixel color = ref Unsafe.Add(ref rowRef, x); + color.ToRgba32(ref rgb); sum += (ulong)(rgb.R + rgb.G + rgb.G); if (x - startX != 0) @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization } } - var operation = new RowOperation(workingRectangle, source, tmpBuffer, intImage, upper, lower, thresholdLimit, clusterSize, startX, endX, startY); + var operation = new RowOperation(workingRectangle, source, intImage, upper, lower, thresholdLimit, clusterSize, startX, endX, startY); ParallelRowIterator.IterateRows( configuration, workingRectangle, @@ -97,7 +97,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization { private readonly Rectangle bounds; private readonly ImageFrame source; - private readonly IMemoryOwner tmpBuffer; private readonly Buffer2D intImage; private readonly TPixel upper; private readonly TPixel lower; @@ -111,7 +110,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization public RowOperation( Rectangle bounds, ImageFrame source, - IMemoryOwner tmpBuffer, Buffer2D intImage, TPixel upper, TPixel lower, @@ -123,7 +121,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization { this.bounds = bounds; this.source = source; - this.tmpBuffer = tmpBuffer; this.intImage = intImage; this.upper = upper; this.lower = lower; @@ -138,17 +135,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization [MethodImpl(InliningOptions.ShortMethod)] public void Invoke(int y) { - Span rgbSpan = this.tmpBuffer.GetSpan(); - ushort x1, y1, x2, y2; + Rgba32 rgb = default; for (ushort x = this.startX; x < this.endX; x++) { - ref Rgb24 rgb = ref rgbSpan[(this.bounds.Width * y) + x]; + TPixel pixel = this.source.PixelBuffer[x, y]; + pixel.ToRgba32(ref rgb); - x1 = (ushort)Math.Max(x - this.startX - this.clusterSize + 1, 0); - x2 = (ushort)Math.Min(x - this.startX + this.clusterSize + 1, this.bounds.Width - 1); - y1 = (ushort)Math.Max(y - this.startY - this.clusterSize + 1, 0); - y2 = (ushort)Math.Min(y - this.startY + this.clusterSize + 1, this.bounds.Height - 1); + var x1 = (ushort)Math.Max(x - this.startX - this.clusterSize + 1, 0); + var x2 = (ushort)Math.Min(x - this.startX + this.clusterSize + 1, this.bounds.Width - 1); + var y1 = (ushort)Math.Max(y - this.startY - this.clusterSize + 1, 0); + var y2 = (ushort)Math.Min(y - this.startY + this.clusterSize + 1, this.bounds.Height - 1); var count = (uint)((x2 - x1) * (y2 - y1)); var sum = (long)Math.Min(this.intImage[x2, y2] - this.intImage[x1, y2] - this.intImage[x2, y1] + this.intImage[x1, y1], long.MaxValue); From a468883110cf413ba6380c29e0bddb41c6356c74 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 2 Apr 2020 17:48:06 +0200 Subject: [PATCH 097/213] Changed startX and endX from ushort to int, Add test with rectangle --- .../AdaptiveThresholdProcessor{TPixel}.cs | 31 ++++++----- .../Binarization/AdaptiveThresholdTests.cs | 52 ++++++++++++++++++- tests/Images/External | 2 +- 3 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs index 109631ab8b..6daf3a8ed7 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs @@ -44,14 +44,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization TPixel lower = this.definition.Lower.ToPixel(); float thresholdLimit = this.definition.ThresholdLimit; - // Used ushort because the values should never exceed max ushort value. - ushort startY = (ushort)intersect.Y; - ushort endY = (ushort)intersect.Bottom; - ushort startX = (ushort)intersect.X; - ushort endX = (ushort)intersect.Right; + int startY = intersect.Y; + int endY = intersect.Bottom; + int startX = intersect.X; + int endX = intersect.Right; - ushort width = (ushort)intersect.Width; - ushort height = (ushort)intersect.Height; + int width = intersect.Width; + int height = intersect.Height; // ClusterSize defines the size of cluster to used to check for average. Tweaked to support up to 4k wide pixels and not more. 4096 / 16 is 256 thus the '-1' byte clusterSize = (byte)Math.Truncate((width / 16f) - 1); @@ -63,10 +62,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); Rgba32 rgb = default; - for (ushort x = startX; x < endX; x++) + for (int x = startX; x < endX; x++) { ulong sum = 0; - for (ushort y = startY; y < endY; y++) + for (int y = startY; y < endY; y++) { Span row = source.GetPixelRowSpan(y); ref TPixel rowRef = ref MemoryMarshal.GetReference(row); @@ -101,9 +100,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization private readonly TPixel upper; private readonly TPixel lower; private readonly float thresholdLimit; - private readonly ushort startX; - private readonly ushort endX; - private readonly ushort startY; + private readonly int startX; + private readonly int endX; + private readonly int startY; private readonly byte clusterSize; [MethodImpl(InliningOptions.ShortMethod)] @@ -115,9 +114,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization TPixel lower, float thresholdLimit, byte clusterSize, - ushort startX, - ushort endX, - ushort startY) + int startX, + int endX, + int startY) { this.bounds = bounds; this.source = source; @@ -137,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization { Rgba32 rgb = default; - for (ushort x = this.startX; x < this.endX; x++) + for (int x = this.startX; x < this.endX; x++) { TPixel pixel = this.source.PixelBuffer[x, y]; pixel.ToRgba32(ref rgb); diff --git a/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs b/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs index 309716eb55..f992ac35b3 100644 --- a/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs +++ b/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Binarization; @@ -15,10 +14,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization [Fact] public void AdaptiveThreshold_UsesDefaults_Works() { + // arrange var expectedThresholdLimit = .85f; Color expectedUpper = Color.White; Color expectedLower = Color.Black; + + // act this.operations.AdaptiveThreshold(); + + // assert AdaptiveThresholdProcessor p = this.Verify(); Assert.Equal(expectedThresholdLimit, p.ThresholdLimit); Assert.Equal(expectedUpper, p.Upper); @@ -28,8 +32,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization [Fact] public void AdaptiveThreshold_SettingThresholdLimit_Works() { + // arrange var expectedThresholdLimit = .65f; + + // act this.operations.AdaptiveThreshold(expectedThresholdLimit); + + // assert AdaptiveThresholdProcessor p = this.Verify(); Assert.Equal(expectedThresholdLimit, p.ThresholdLimit); Assert.Equal(Color.White, p.Upper); @@ -39,9 +48,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization [Fact] public void AdaptiveThreshold_SettingUpperLowerThresholds_Works() { + // arrange Color expectedUpper = Color.HotPink; Color expectedLower = Color.Yellow; + + // act this.operations.AdaptiveThreshold(expectedUpper, expectedLower); + + // assert AdaptiveThresholdProcessor p = this.Verify(); Assert.Equal(expectedUpper, p.Upper); Assert.Equal(expectedLower, p.Lower); @@ -50,16 +64,39 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization [Fact] public void AdaptiveThreshold_SettingUpperLowerWithThresholdLimit_Works() { + // arrange var expectedThresholdLimit = .77f; Color expectedUpper = Color.HotPink; Color expectedLower = Color.Yellow; + + // act this.operations.AdaptiveThreshold(expectedUpper, expectedLower, expectedThresholdLimit); + + // assert AdaptiveThresholdProcessor p = this.Verify(); Assert.Equal(expectedThresholdLimit, p.ThresholdLimit); Assert.Equal(expectedUpper, p.Upper); Assert.Equal(expectedLower, p.Lower); } + [Fact] + public void AdaptiveThreshold_SettingUpperLowerWithThresholdLimit_WithRectangle_Works() + { + // arrange + var expectedThresholdLimit = .77f; + Color expectedUpper = Color.HotPink; + Color expectedLower = Color.Yellow; + + // act + this.operations.AdaptiveThreshold(expectedUpper, expectedLower, expectedThresholdLimit, this.rect); + + // assert + AdaptiveThresholdProcessor p = this.Verify(this.rect); + Assert.Equal(expectedThresholdLimit, p.ThresholdLimit); + Assert.Equal(expectedUpper, p.Upper); + Assert.Equal(expectedLower, p.Lower); + } + [Theory] [WithFile(TestImages.Png.Bradley01, PixelTypes.Rgba32)] [WithFile(TestImages.Png.Bradley02, PixelTypes.Rgba32)] @@ -73,5 +110,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Binarization image.CompareToReferenceOutput(ImageComparer.Exact, provider); } } + + [Theory] + [WithFile(TestImages.Png.Bradley02, PixelTypes.Rgba32)] + public void AdaptiveThreshold_WithRectangle_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage()) + { + image.Mutate(img => img.AdaptiveThreshold(Color.White, Color.Black, new Rectangle(60, 90, 200, 30))); + image.DebugSave(provider); + image.CompareToReferenceOutput(ImageComparer.Exact, provider); + } + } } } diff --git a/tests/Images/External b/tests/Images/External index c04c8b73a9..6fdc6d19b1 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit c04c8b73a99c1b198597ae640394d91ddd8e033b +Subproject commit 6fdc6d19b101dc1c00a297d3e92257df60c413d0 From 1c926703a87f93dc77b55fa1304074a1ae59e459 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 2 Apr 2020 19:59:24 +0200 Subject: [PATCH 098/213] Using pixel row span to access the pixels --- .../Binarization/AdaptiveThresholdProcessor{TPixel}.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs index 6daf3a8ed7..7b3e10b0d8 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs @@ -135,10 +135,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization public void Invoke(int y) { Rgba32 rgb = default; + Span pixelRow = this.source.GetPixelRowSpan(y); for (int x = this.startX; x < this.endX; x++) { - TPixel pixel = this.source.PixelBuffer[x, y]; + TPixel pixel = pixelRow[x]; pixel.ToRgba32(ref rgb); var x1 = (ushort)Math.Max(x - this.startX - this.clusterSize + 1, 0); From 1c7c491472170cc3f38382431190103673036b77 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 2 Apr 2020 21:40:49 +0100 Subject: [PATCH 099/213] Remove GC, add MethodImpl, use Buffer --- Directory.Build.props | 24 +++++++++---------- .../Common/Helpers/InliningOptions.cs | 10 ++++++-- src/ImageSharp/Formats/Png/Zlib/Deflater.cs | 2 -- .../Formats/Png/Zlib/DeflaterEngine.cs | 5 ++-- .../Formats/Png/Zlib/DeflaterHuffman.cs | 5 +--- .../Formats/Png/Zlib/DeflaterPendingBuffer.cs | 2 -- 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 12a4a5c2a3..50c09fbb3c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -31,21 +31,21 @@ - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE;SUPPORTS_HOTPATH $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index 069a426d75..895b6250f6 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // Uncomment this for verbose profiler results. DO NOT PUSH TO MAIN! @@ -13,10 +13,16 @@ namespace SixLabors.ImageSharp internal static class InliningOptions { #if PROFILING + public const MethodImplOptions HotPath = MethodImplOptions.NoInlining; public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining; #else +#if SUPPORTS_HOTPATH + public const MethodImplOptions HotPath = MethodImplOptions.AggressiveOptimization; +#else + public const MethodImplOptions HotPath = MethodImplOptions.AggressiveInlining; +#endif public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining; #endif public const MethodImplOptions ColdPath = MethodImplOptions.NoInlining; } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Png/Zlib/Deflater.cs b/src/ImageSharp/Formats/Png/Zlib/Deflater.cs index 7398b089bb..2083edab1c 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Deflater.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Deflater.cs @@ -288,8 +288,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib this.engine = null; this.isDisposed = true; } - - GC.SuppressFinalize(this); } } } diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs index 1a8bb4ab04..c1c86a98be 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs @@ -362,7 +362,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib more = this.inputEnd - this.inputOff; } - Array.Copy(this.inputBuf, this.inputOff, this.window, this.strstart + this.lookahead, more); + Buffer.BlockCopy(this.inputBuf, this.inputOff, this.window, this.strstart + this.lookahead, more); this.inputOff += more; this.lookahead += more; @@ -397,8 +397,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib this.isDisposed = true; } - - GC.SuppressFinalize(this); } [MethodImpl(InliningOptions.ShortMethod)] @@ -464,6 +462,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// /// The current match. /// True if a match greater than the minimum length is found + [MethodImpl(InliningOptions.HotPath)] private bool FindLongestMatch(int curMatch) { int match; diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs index 543a1fe302..8380f7d5b9 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs @@ -413,8 +413,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib this.distTree = null; this.isDisposed = true; } - - GC.SuppressFinalize(this); } [MethodImpl(InliningOptions.ShortMethod)] @@ -553,6 +551,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib } } + [MethodImpl(InliningOptions.HotPath)] public void BuildTree() { int numSymbols = this.elementCount; @@ -964,8 +963,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib this.isDisposed = true; } - - GC.SuppressFinalize(this); } } } diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs index 731c9e80f0..0414ca2f87 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs @@ -172,8 +172,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib this.bufferMemoryOwner = null; this.isDisposed = true; } - - GC.SuppressFinalize(this); } } } From 50aa77e3a002df178afd823d4b391e9b5ea10db8 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 2 Apr 2020 23:15:48 +0200 Subject: [PATCH 100/213] Review changes --- .../AdaptiveThresholdProcessor{TPixel}.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs index 7b3e10b0d8..dd8833ad96 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs @@ -18,7 +18,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization where TPixel : unmanaged, IPixel { private readonly AdaptiveThresholdProcessor definition; - private readonly PixelOperations pixelOpInstance; /// /// Initializes a new instance of the class. @@ -30,7 +29,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization public AdaptiveThresholdProcessor(Configuration configuration, AdaptiveThresholdProcessor definition, Image source, Rectangle sourceRectangle) : base(configuration, source, sourceRectangle) { - this.pixelOpInstance = PixelOperations.Instance; this.definition = definition; } @@ -58,9 +56,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Using pooled 2d buffer for integer image table and temp memory to hold Rgb24 converted pixel data. using (Buffer2D intImage = this.Configuration.MemoryAllocator.Allocate2D(width, height)) { - // Defines the rectangle section of the image to work on. - var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); - Rgba32 rgb = default; for (int x = startX; x < endX; x++) { @@ -84,10 +79,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization } } - var operation = new RowOperation(workingRectangle, source, intImage, upper, lower, thresholdLimit, clusterSize, startX, endX, startY); + var operation = new RowOperation(intersect, source, intImage, upper, lower, thresholdLimit, clusterSize, startX, endX, startY); ParallelRowIterator.IterateRows( configuration, - workingRectangle, + intersect, in operation); } } @@ -142,10 +137,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization TPixel pixel = pixelRow[x]; pixel.ToRgba32(ref rgb); - var x1 = (ushort)Math.Max(x - this.startX - this.clusterSize + 1, 0); - var x2 = (ushort)Math.Min(x - this.startX + this.clusterSize + 1, this.bounds.Width - 1); - var y1 = (ushort)Math.Max(y - this.startY - this.clusterSize + 1, 0); - var y2 = (ushort)Math.Min(y - this.startY + this.clusterSize + 1, this.bounds.Height - 1); + var x1 = Math.Max(x - this.startX - this.clusterSize + 1, 0); + var x2 = Math.Min(x - this.startX + this.clusterSize + 1, this.bounds.Width - 1); + var y1 = Math.Max(y - this.startY - this.clusterSize + 1, 0); + var y2 = Math.Min(y - this.startY + this.clusterSize + 1, this.bounds.Height - 1); var count = (uint)((x2 - x1) * (y2 - y1)); var sum = (long)Math.Min(this.intImage[x2, y2] - this.intImage[x1, y2] - this.intImage[x2, y1] + this.intImage[x1, y1], long.MaxValue); From ee016f61157986fe50c50ff13390d6c485972050 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 3 Apr 2020 11:48:15 +0200 Subject: [PATCH 101/213] Minor formatting change --- src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs index 4fc78a9588..3279d96e3a 100644 --- a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs +++ b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The image this method extends. /// Upper (white) color for thresholding. - /// Lower (black) color for thresholding + /// Lower (black) color for thresholding. /// Rectangle region to apply the processor on. /// The . public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, Color upper, Color lower, Rectangle rectangle) @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing ///
/// The iptc metadata to write. + /// + /// Thrown if the IPTC profile size exceeds the limit of 65533 bytes. + /// private void WriteIptcProfile(IptcProfile iptcProfile) { + const int Max = 65533; if (iptcProfile is null || !iptcProfile.Values.Any()) { return; @@ -714,6 +718,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg return; } + if (data.Length > Max) + { + throw new ImageFormatException($"Iptc profile size exceeds limit of {Max} bytes"); + } + var app13Length = 2 + ProfileResolver.AdobePhotoshopApp13Marker.Length + ProfileResolver.AdobeImageResourceBlockMarker.Length + ProfileResolver.AdobeIptcMarker.Length + From 7e9d5533614ee42c2b1e53406776725cfc61526c Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 16 Apr 2020 13:21:35 +0200 Subject: [PATCH 126/213] Remove by tag now removes all entry's not just the first. Similar GetValue now returns a list of entrys instead of just one --- .../Metadata/Profiles/IPTC/IptcProfile.cs | 45 +++++++++++++---- .../Profiles/IPTC/IptcProfileTests.cs | 49 +++++++++++++++++++ 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index 119c6f2b50..f4b4f10432 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -79,42 +79,67 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc public IptcProfile DeepClone() => new IptcProfile(this); /// - /// Returns the value with the specified tag. + /// Returns all value with the specified tag. /// /// The tag of the iptc value. - /// The value with the specified tag. - public IptcValue GetValue(IptcTag tag) + /// The values found with the specified tag. + public List GetValues(IptcTag tag) { + var values = new List(); foreach (IptcValue iptcValue in this.Values) { if (iptcValue.Tag == tag) { - return iptcValue; + values.Add(iptcValue); } } - return null; + return values; } /// - /// Removes the value with the specified tag. + /// Removes all values with the specified tag. /// - /// The tag of the iptc value. + /// The tag of the iptc value to remove. /// True when the value was found and removed. public bool RemoveValue(IptcTag tag) { this.Initialize(); - for (int i = 0; i < this.values.Count; i++) + bool removed = false; + for (int i = this.values.Count - 1; i >= 0; i--) { if (this.values[i].Tag == tag) { this.values.RemoveAt(i); - return true; + removed = true; + } + } + + return removed; + } + + /// + /// Removes values with the specified tag and value. + /// + /// The tag of the iptc value to remove. + /// The value of the iptc item to remove. + /// True when the value was found and removed. + public bool RemoveValue(IptcTag tag, string value) + { + this.Initialize(); + + bool removed = false; + for (int i = this.values.Count - 1; i >= 0; i--) + { + if (this.values[i].Tag == tag && this.values[i].Value.Equals(value)) + { + this.values.RemoveAt(i); + removed = true; } } - return false; + return removed; } ///
diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index f15a0992d2..9f8f8088df 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -215,6 +215,55 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC ContainsIptcValue(values, tag, expectedValue); } + [Fact] + public void IptcProfile_RemoveByTag_RemovesAllEntrys() + { + // arange + var profile = new IptcProfile(); + profile.SetValue(IptcTag.Byline, "test"); + profile.SetValue(IptcTag.Byline, "test2"); + + // act + var result = profile.RemoveValue(IptcTag.Byline); + + // assert + Assert.True(result, "removed result should be true"); + Assert.Empty(profile.Values); + } + + [Fact] + public void IptcProfile_RemoveByTagAndValue_Works() + { + // arange + var profile = new IptcProfile(); + profile.SetValue(IptcTag.Byline, "test"); + profile.SetValue(IptcTag.Byline, "test2"); + + // act + var result = profile.RemoveValue(IptcTag.Byline, "test2"); + + // assert + Assert.True(result, "removed result should be true"); + ContainsIptcValue(profile.Values, IptcTag.Byline, "test"); + } + + [Fact] + public void IptcProfile_GetValue_RetrievesAllEntrys() + { + // arange + var profile = new IptcProfile(); + profile.SetValue(IptcTag.Byline, "test"); + profile.SetValue(IptcTag.Byline, "test2"); + profile.SetValue(IptcTag.Caption, "test"); + + // act + List result = profile.GetValues(IptcTag.Byline); + + // assert + Assert.NotNull(result); + Assert.Equal(2, result.Count); + } + private static void ContainsIptcValue(IEnumerable values, IptcTag tag, string value) { Assert.True(values.Any(val => val.Tag == tag), $"Missing iptc tag {tag}"); From 216708521458696498ab608da854b56b73a9dd90 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 17 Apr 2020 13:31:24 +0200 Subject: [PATCH 127/213] Limit length of iptc values according to the spec --- .../Metadata/Profiles/IPTC/IptcProfile.cs | 77 ++++------- .../Metadata/Profiles/IPTC/IptcTag.cs | 119 ++++++++++------- .../Profiles/IPTC/IptcTagExtensions.cs | 121 ++++++++++++++++++ .../Metadata/Profiles/IPTC/IptcValue.cs | 37 +++++- .../Metadata/Profiles/IPTC/README.md | 6 +- .../Profiles/IPTC/IptcProfileTests.cs | 56 ++++++-- 6 files changed, 297 insertions(+), 119 deletions(-) create mode 100644 src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index f4b4f10432..b86f6dff2d 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -37,6 +37,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc this.Initialize(); } + /// + /// Initializes a new instance of the class + /// by making a copy from another IPTC profile. + /// + /// The other IPTC profile, from which the clone should be made from. private IptcProfile(IptcProfile other) { Guard.NotNull(other, nameof(other)); @@ -85,16 +90,16 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// The values found with the specified tag. public List GetValues(IptcTag tag) { - var values = new List(); + var iptcValues = new List(); foreach (IptcValue iptcValue in this.Values) { if (iptcValue.Tag == tag) { - values.Add(iptcValue); + iptcValues.Add(iptcValue); } } - return values; + return iptcValues; } /// @@ -157,21 +162,26 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc } /// - /// Sets the value of the specified tag. + /// Sets the value for the specified tag. /// /// The tag of the iptc value. /// The encoding to use when storing the bytes. /// The value. - public void SetValue(IptcTag tag, Encoding encoding, string value) + /// + /// Indicates if length restrictions from the specification should be followed strictly. + /// Defaults to true. + /// + public void SetValue(IptcTag tag, Encoding encoding, string value, bool strict = true) { Guard.NotNull(encoding, nameof(encoding)); - if (!this.IsRepeatable(tag)) + if (!tag.IsRepeatable()) { foreach (IptcValue iptcValue in this.Values) { if (iptcValue.Tag == tag) { + iptcValue.Strict = strict; iptcValue.Encoding = encoding; iptcValue.Value = value; return; @@ -179,7 +189,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc } } - this.values.Add(new IptcValue(tag, encoding, value)); + this.values.Add(new IptcValue(tag, encoding, value, strict)); } /// @@ -187,7 +197,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// /// The tag of the iptc value. /// The value. - public void SetValue(IptcTag tag, string value) => this.SetValue(tag, Encoding.UTF8, value); + /// + /// Indicates if length restrictions from the specification should be followed strictly. + /// Defaults to true. + /// + public void SetValue(IptcTag tag, string value, bool strict = true) => this.SetValue(tag, Encoding.UTF8, value, strict); /// /// Updates the data of the profile. @@ -251,56 +265,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc if ((count > 0) && (i + count <= this.Data.Length)) { Buffer.BlockCopy(this.Data, i, iptcData, 0, count); - this.values.Add(new IptcValue(tag, iptcData)); + this.values.Add(new IptcValue(tag, iptcData, false)); } i += count; } } - - private bool IsRepeatable(IptcTag tag) - { - switch (tag) - { - case IptcTag.RecordVersion: - case IptcTag.ObjectType: - case IptcTag.Name: - case IptcTag.EditStatus: - case IptcTag.EditorialUpdate: - case IptcTag.Urgency: - case IptcTag.Category: - case IptcTag.FixtureIdentifier: - case IptcTag.ReleaseDate: - case IptcTag.ReleaseTime: - case IptcTag.ExpirationDate: - case IptcTag.ExpirationTime: - case IptcTag.SpecialInstructions: - case IptcTag.ActionAdvised: - case IptcTag.CreatedDate: - case IptcTag.CreatedTime: - case IptcTag.DigitalCreationDate: - case IptcTag.DigitalCreationTime: - case IptcTag.OriginatingProgram: - case IptcTag.ProgramVersion: - case IptcTag.ObjectCycle: - case IptcTag.City: - case IptcTag.SubLocation: - case IptcTag.ProvinceState: - case IptcTag.CountryCode: - case IptcTag.Country: - case IptcTag.OriginalTransmissionReference: - case IptcTag.Headline: - case IptcTag.Credit: - case IptcTag.Source: - case IptcTag.CopyrightNotice: - case IptcTag.Caption: - case IptcTag.ImageType: - case IptcTag.ImageOrientation: - return false; - - default: - return true; - } - } } } diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs index cd0b620720..135c41e51f 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs @@ -4,7 +4,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { /// - /// All iptc tags. + /// All iptc tags relevant for images. /// public enum IptcTag { @@ -14,222 +14,245 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc Unknown = -1, /// - /// Record version, not repeatable. + /// Record version identifying the version of the Information Interchange Model. + /// Not repeatable. Max length is 2. /// RecordVersion = 0, /// - /// Object type, not repeatable. + /// Object type, not repeatable. Max Length is 67. /// ObjectType = 3, /// - /// Object attribute. + /// Object attribute. Max length is 68. /// ObjectAttribute = 4, /// - /// Object Name, not repeatable. + /// Object Name, not repeatable. Max length is 64. /// Name = 5, /// - /// Edit status, not repeatable. + /// Edit status, not repeatable. Max length is 64. /// EditStatus = 7, /// - /// Editorial update, not repeatable. + /// Editorial update, not repeatable. Max length is 2. /// EditorialUpdate = 8, /// - /// Urgency, not repeatable. + /// Urgency, not repeatable. Max length is 2. /// Urgency = 10, /// - /// Subject Reference. + /// Subject Reference. Max length is 236. /// SubjectReference = 12, /// - /// Category, not repeatable. + /// Category, not repeatable. Max length is 3. /// Category = 15, /// - /// Supplemental categories. + /// Supplemental categories. Max length is 32. /// SupplementalCategories = 20, /// - /// Fixture identifier, not repeatable. + /// Fixture identifier, not repeatable. Max length is 32. /// FixtureIdentifier = 22, /// - /// Keywords. + /// Keywords. Max length is 64. /// Keywords = 25, /// - /// Location code. + /// Location code. Max length is 3. /// LocationCode = 26, /// - /// Location name. + /// Location name. Max length is 64. /// LocationName = 27, /// - /// Release date, not repeatable. + /// Release date. Format should be CCYYMMDD, + /// e.g. "19890317" indicates data for release on 17 March 1989. + /// Not repeatable, max length is 8. /// ReleaseDate = 30, /// - /// Release time, not repeatable. + /// Release time. Format should be HHMMSS±HHMM, + /// e.g. "090000-0500" indicates object for use after 0900 in + /// New York (five hours behind UTC) + /// Not repeatable, max length is 11. /// ReleaseTime = 35, /// - /// Expiration date, not repeatable. + /// Expiration date. Format should be CCYYMMDD, + /// e.g. "19890317" indicates data for release on 17 March 1989. + /// Not repeatable, max length is 8. /// ExpirationDate = 37, /// - /// Expiration time, not repeatable. + /// Expiration time. Format should be HHMMSS±HHMM, + /// e.g. "090000-0500" indicates object for use after 0900 in + /// New York (five hours behind UTC) + /// Not repeatable, max length is 11. /// ExpirationTime = 38, /// - /// Special instructions, not repeatable. + /// Special instructions, not repeatable. Max length is 256. /// SpecialInstructions = 40, /// - /// Action advised, not repeatable. + /// Action advised, not repeatable. Max length is 2. /// ActionAdvised = 42, /// - /// Reference service. + /// Reference service. Max length is 10. /// ReferenceService = 45, /// - /// Reference date. + /// Reference date. Format should be CCYYMMDD, + /// e.g. "19890317" indicates data for release on 17 March 1989. + /// Not repeatable, max length is 8. /// ReferenceDate = 47, /// - /// ReferenceNumber. + /// ReferenceNumber. Max length is 8. /// ReferenceNumber = 50, /// - /// Created date, not repeatable. + /// Created date. Format should be CCYYMMDD, + /// e.g. "19890317" indicates data for release on 17 March 1989. + /// Not repeatable, max length is 8. /// CreatedDate = 55, /// - /// Created time, not repeatable. + /// Created time. Format should be HHMMSS±HHMM, + /// e.g. "090000-0500" indicates object for use after 0900 in + /// New York (five hours behind UTC) + /// Not repeatable, max length is 11. /// CreatedTime = 60, /// - /// Digital creation date, not repeatable. + /// Digital creation date. Format should be CCYYMMDD, + /// e.g. "19890317" indicates data for release on 17 March 1989. + /// Not repeatable, max length is 8. /// DigitalCreationDate = 62, /// - /// Digital creation time, not repeatable. + /// Digital creation time. Format should be HHMMSS±HHMM, + /// e.g. "090000-0500" indicates object for use after 0900 in + /// New York (five hours behind UTC) + /// Not repeatable, max length is 11. /// DigitalCreationTime = 63, /// - /// Originating program, not repeatable. + /// Originating program, not repeatable. Max length is 32. /// OriginatingProgram = 65, /// - /// Program version, not repeatable. + /// Program version, not repeatable. Max length is 10. /// ProgramVersion = 70, /// - /// Object cycle, not repeatable. + /// Object cycle, not repeatable. Max length is 1. /// ObjectCycle = 75, /// - /// Byline. + /// Byline. Max length is 32. /// Byline = 80, /// - /// Byline title. + /// Byline title. Max length is 32. /// BylineTitle = 85, /// - /// City, not repeatable. + /// City, not repeatable. Max length is 32. /// City = 90, /// - /// Sub location, not repeatable. + /// Sub location, not repeatable. Max length is 32. /// SubLocation = 92, /// - /// Province/State, not repeatable. + /// Province/State, not repeatable. Max length is 32. /// ProvinceState = 95, /// - /// Country code, not repeatable. + /// Country code, not repeatable. Max length is 3. /// CountryCode = 100, /// - /// Country, not repeatable. + /// Country, not repeatable. Max length is 64. /// Country = 101, /// - /// Original transmission reference, not repeatable. + /// Original transmission reference, not repeatable. Max length is 32. /// OriginalTransmissionReference = 103, /// - /// Headline, not repeatable. + /// Headline, not repeatable. Max length is 256. /// Headline = 105, /// - /// Credit, not repeatable. + /// Credit, not repeatable. Max length is 32. /// Credit = 110, /// - /// Source, not repeatable. + /// Source, not repeatable. Max length is 32. /// Source = 115, /// - /// Copyright notice, not repeatable. + /// Copyright notice, not repeatable. Max length is 128. /// CopyrightNotice = 116, /// - /// Contact. + /// Contact. Max length 128. /// Contact = 118, /// - /// Caption, not repeatable. + /// Caption, not repeatable. Max length is 2000. /// Caption = 120, @@ -239,17 +262,17 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc LocalCaption = 121, /// - /// Caption writer. + /// Caption writer. Max length is 32. /// CaptionWriter = 122, /// - /// Image type, not repeatable. + /// Image type, not repeatable. Max length is 2. /// ImageType = 130, /// - /// Image orientation, not repeatable. + /// Image orientation, not repeatable. Max length is 1. /// ImageOrientation = 131, diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs new file mode 100644 index 0000000000..88d463767d --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs @@ -0,0 +1,121 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc +{ + /// + /// Extension methods for IPTC tags. + /// + public static class IptcTagExtensions + { + /// + /// Maximum length of the IPTC value with the given tag according to the specification. + /// + /// The tag to check the max length for. + /// The maximum length. + public static int MaxLength(this IptcTag tag) + { + return tag switch + { + IptcTag.RecordVersion => 2, + IptcTag.ObjectType => 67, + IptcTag.ObjectAttribute => 68, + IptcTag.Name => 64, + IptcTag.EditStatus => 64, + IptcTag.EditorialUpdate => 2, + IptcTag.Urgency => 1, + IptcTag.SubjectReference => 236, + IptcTag.Category => 3, + IptcTag.SupplementalCategories => 32, + IptcTag.FixtureIdentifier => 32, + IptcTag.Keywords => 64, + IptcTag.LocationCode => 3, + IptcTag.LocationName => 64, + IptcTag.ReleaseDate => 8, + IptcTag.ReleaseTime => 11, + IptcTag.ExpirationDate => 8, + IptcTag.ExpirationTime => 11, + IptcTag.SpecialInstructions => 256, + IptcTag.ActionAdvised => 2, + IptcTag.ReferenceService => 10, + IptcTag.ReferenceDate => 8, + IptcTag.ReferenceNumber => 8, + IptcTag.CreatedDate => 8, + IptcTag.CreatedTime => 11, + IptcTag.DigitalCreationDate => 8, + IptcTag.DigitalCreationTime => 11, + IptcTag.OriginatingProgram => 32, + IptcTag.ProgramVersion => 10, + IptcTag.ObjectCycle => 1, + IptcTag.Byline => 32, + IptcTag.BylineTitle => 32, + IptcTag.City => 32, + IptcTag.SubLocation => 32, + IptcTag.ProvinceState => 32, + IptcTag.CountryCode => 3, + IptcTag.Country => 64, + IptcTag.OriginalTransmissionReference => 32, + IptcTag.Headline => 256, + IptcTag.Credit => 32, + IptcTag.Source => 32, + IptcTag.CopyrightNotice => 128, + IptcTag.Contact => 128, + IptcTag.Caption => 2000, + IptcTag.CaptionWriter => 32, + IptcTag.ImageType => 2, + IptcTag.ImageOrientation => 1, + _ => 256 + }; + } + + /// + /// Determines if the given tag can be repeated according to the specification. + /// + /// The tag to check. + /// True, if the tag can occur multiple times. + public static bool IsRepeatable(this IptcTag tag) + { + switch (tag) + { + case IptcTag.RecordVersion: + case IptcTag.ObjectType: + case IptcTag.Name: + case IptcTag.EditStatus: + case IptcTag.EditorialUpdate: + case IptcTag.Urgency: + case IptcTag.Category: + case IptcTag.FixtureIdentifier: + case IptcTag.ReleaseDate: + case IptcTag.ReleaseTime: + case IptcTag.ExpirationDate: + case IptcTag.ExpirationTime: + case IptcTag.SpecialInstructions: + case IptcTag.ActionAdvised: + case IptcTag.CreatedDate: + case IptcTag.CreatedTime: + case IptcTag.DigitalCreationDate: + case IptcTag.DigitalCreationTime: + case IptcTag.OriginatingProgram: + case IptcTag.ProgramVersion: + case IptcTag.ObjectCycle: + case IptcTag.City: + case IptcTag.SubLocation: + case IptcTag.ProvinceState: + case IptcTag.CountryCode: + case IptcTag.Country: + case IptcTag.OriginalTransmissionReference: + case IptcTag.Headline: + case IptcTag.Credit: + case IptcTag.Source: + case IptcTag.CopyrightNotice: + case IptcTag.Caption: + case IptcTag.ImageType: + case IptcTag.ImageOrientation: + return false; + + default: + return true; + } + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs index a5977fd274..2c2cf59954 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs @@ -28,24 +28,35 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc } this.Tag = other.Tag; + this.Strict = other.Strict; } - internal IptcValue(IptcTag tag, byte[] value) + internal IptcValue(IptcTag tag, byte[] value, bool strict) { Guard.NotNull(value, nameof(value)); + this.Strict = strict; this.Tag = tag; this.data = value; this.encoding = Encoding.UTF8; } - internal IptcValue(IptcTag tag, Encoding encoding, string value) + internal IptcValue(IptcTag tag, Encoding encoding, string value, bool strict) { + this.Strict = strict; this.Tag = tag; this.encoding = encoding; this.Value = value; } + internal IptcValue(IptcTag tag, string value, bool strict) + { + this.Strict = strict; + this.Tag = tag; + this.encoding = Encoding.UTF8; + this.Value = value; + } + /// /// Gets or sets the encoding to use for the Value. /// @@ -66,6 +77,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// public IptcTag Tag { get; } + /// + /// Gets or sets a value indicating whether to be enforce value length restrictions according + /// to the specification. + /// + public bool Strict { get; set; } + /// /// Gets or sets the value. /// @@ -76,11 +93,23 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { if (string.IsNullOrEmpty(value)) { - this.data = new byte[0]; + this.data = Array.Empty(); } else { - this.data = this.encoding.GetBytes(value); + int maxLength = this.Tag.MaxLength(); + byte[] valueBytes; + if (this.Strict && value.Length > maxLength) + { + var cappedValue = value.Substring(0, maxLength); + valueBytes = this.encoding.GetBytes(cappedValue); + } + else + { + valueBytes = this.encoding.GetBytes(value); + } + + this.data = valueBytes; } } } diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/README.md b/src/ImageSharp/Metadata/Profiles/IPTC/README.md index 0b0efc967d..1217ca0c70 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/README.md +++ b/src/ImageSharp/Metadata/Profiles/IPTC/README.md @@ -1,9 +1,11 @@ IPTC source code is from [Magick.NET](https://github.com/dlemstra/Magick.NET) -Information about IPTC can be found here in the folowing sources: +Information about IPTC can be found here in the following sources: - [metacpan.org, APP13-segment](https://metacpan.org/pod/Image::MetaData::JPEG::Structures#Structure-of-a-Photoshop-style-APP13-segment) - [iptc.org](https://www.iptc.org/std/photometadata/documentation/userguide/) -- [Adobe File Formats Specification](http://oldschoolprg.x10.mx/downloads/ps6ffspecsv2.pdf) \ No newline at end of file +- [Adobe File Formats Specification](http://oldschoolprg.x10.mx/downloads/ps6ffspecsv2.pdf) + +- [Tag Overview](https://exiftool.org/TagNames/IPTC.html) \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index 9f8f8088df..321c7fe5c0 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -15,6 +16,31 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC { private static JpegDecoder JpegDecoder => new JpegDecoder() { IgnoreMetadata = false }; + public static IEnumerable allIptcTags() + { + foreach (object tag in Enum.GetValues(typeof(IptcTag))) + { + yield return new object[] { tag }; + } + } + + [Theory] + [MemberData("allIptcTags")] + public void IptcProfile_SetValue_WithStrictOption_Works(IptcTag tag) + { + // arrange + var profile = new IptcProfile(); + var value = new string('s', tag.MaxLength() + 1); + var expectedLength = tag.MaxLength(); + + // act + profile.SetValue(tag, value); + + // assert + IptcValue actual = profile.GetValues(tag).First(); + Assert.Equal(expectedLength, actual.Value.Length); + } + [Theory] [WithFile(TestImages.Jpeg.Baseline.Iptc, PixelTypes.Rgba32)] public void ReadIptcMetadata_Works(TestImageProvider provider) @@ -91,16 +117,17 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC // assert Assert.Equal(2, clone.Values.Count()); - ContainsIptcValue(clone.Values, IptcTag.CaptionWriter, captionWriter); - ContainsIptcValue(clone.Values, IptcTag.Caption, "changed"); - ContainsIptcValue(profile.Values, IptcTag.Caption, caption); + var cloneValues = clone.Values.ToList(); + ContainsIptcValue(cloneValues, IptcTag.CaptionWriter, captionWriter); + ContainsIptcValue(cloneValues, IptcTag.Caption, "changed"); + ContainsIptcValue(profile.Values.ToList(), IptcTag.Caption, caption); } [Fact] public void IptcValue_CloneIsDeep() { // arrange - var iptcValue = new IptcValue(IptcTag.Caption, System.Text.Encoding.UTF8, "test"); + var iptcValue = new IptcValue(IptcTag.Caption, System.Text.Encoding.UTF8, "test", true); // act IptcValue clone = iptcValue.DeepClone(); @@ -132,6 +159,13 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC ContainsIptcValue(iptcValues, IptcTag.Caption, expectedCaption); } + [Fact] + public void IptcProfile_SetNewValue_RespectsMaxLength() + { + // arrange + var profile = new IptcProfile(); + } + [Theory] [InlineData(IptcTag.ObjectAttribute)] [InlineData(IptcTag.SubjectReference)] @@ -153,10 +187,10 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC var profile = new IptcProfile(); var expectedValue1 = "test"; var expectedValue2 = "another one"; - profile.SetValue(tag, expectedValue1); + profile.SetValue(tag, expectedValue1, false); // act - profile.SetValue(tag, expectedValue2); + profile.SetValue(tag, expectedValue2, false); // assert var values = profile.Values.ToList(); @@ -204,10 +238,10 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC // arrange var profile = new IptcProfile(); var expectedValue = "another one"; - profile.SetValue(tag, "test"); + profile.SetValue(tag, "test", false); // act - profile.SetValue(tag, expectedValue); + profile.SetValue(tag, expectedValue, false); // assert var values = profile.Values.ToList(); @@ -244,7 +278,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC // assert Assert.True(result, "removed result should be true"); - ContainsIptcValue(profile.Values, IptcTag.Byline, "test"); + ContainsIptcValue(profile.Values.ToList(), IptcTag.Byline, "test"); } [Fact] @@ -264,10 +298,10 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC Assert.Equal(2, result.Count); } - private static void ContainsIptcValue(IEnumerable values, IptcTag tag, string value) + private static void ContainsIptcValue(List values, IptcTag tag, string value) { Assert.True(values.Any(val => val.Tag == tag), $"Missing iptc tag {tag}"); - Assert.True(values.Contains(new IptcValue(tag, System.Text.Encoding.UTF8.GetBytes(value))), $"expected iptc value '{value}' was not found for tag '{tag}'"); + Assert.True(values.Contains(new IptcValue(tag, System.Text.Encoding.UTF8.GetBytes(value), false)), $"expected iptc value '{value}' was not found for tag '{tag}'"); } private static Image WriteAndReadJpeg(Image image) From 9df82f57ce937f69138b3d57ec5948c39862b3e8 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 18 Apr 2020 11:37:44 +0100 Subject: [PATCH 128/213] global property store on configuration on processing context --- src/ImageSharp/Configuration.cs | 9 +++ .../GraphicOptionsDefaultsExtensions.cs | 67 +++++++++++++++++++ .../DefaultImageProcessorContext{TPixel}.cs | 5 ++ .../Extensions/Drawing/DrawImageExtensions.cs | 8 +-- .../Extensions/Filters/LomographExtensions.cs | 8 +-- .../Extensions/Filters/PolaroidExtensions.cs | 6 +- .../Overlays/BackgroundColorExtensions.cs | 4 +- .../Extensions/Overlays/GlowExtensions.cs | 10 +-- .../Extensions/Overlays/VignetteExtensions.cs | 10 +-- .../Processing/IImageProcessingContext.cs | 7 ++ .../Processors/Filters/LomographProcessor.cs | 9 ++- .../Filters/LomographProcessor{TPixel}.cs | 4 +- .../Processors/Filters/PolaroidProcessor.cs | 9 ++- .../Filters/PolaroidProcessor{TPixel}.cs | 6 +- .../Processors/Overlays/GlowProcessor.cs | 19 ------ .../Processors/Overlays/VignetteProcessor.cs | 9 --- .../Processing/FakeImageOperationsProvider.cs | 2 + 17 files changed, 136 insertions(+), 56 deletions(-) create mode 100644 src/ImageSharp/GraphicOptionsDefaultsExtensions.cs diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 47c7c54ea0..b2d819f1c0 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Net.Http; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; @@ -27,6 +28,8 @@ namespace SixLabors.ImageSharp private int maxDegreeOfParallelism = Environment.ProcessorCount; + private Dictionary properties = new Dictionary(); + /// /// Initializes a new instance of the class. /// @@ -73,6 +76,12 @@ namespace SixLabors.ImageSharp } } + /// + /// Gets a set of properties for the Congiguration. + /// + /// This can be used for storing global settings and defaults to be accessable to processors. + public IDictionary Properties => this.properties; + /// /// Gets the currently registered s. /// diff --git a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs new file mode 100644 index 0000000000..3d86a5b0c1 --- /dev/null +++ b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs @@ -0,0 +1,67 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Processing; + +namespace SixLabors.ImageSharp +{ + /// + /// Adds extensions that allow the processing of images to the type. + /// + public static class GraphicOptionsDefaultsExtensions + { + /// + /// Sets the default options against the image processing context. + /// + /// The image processing context to store default against. + /// The default options to use. + public static void SetDefaultOptions(this IImageProcessingContext context, GraphicsOptions options) + { + context.Properties[typeof(GraphicsOptions)] = options; + } + + /// + /// Sets the default options against the configuration. + /// + /// The image processing context to store default against. + /// The default options to use. + public static void SetDefaultOptions(this Configuration context, GraphicsOptions options) + { + context.Properties[typeof(GraphicsOptions)] = options; + } + + /// + /// Gets the default options against the image processing context. + /// + /// The image processing context to retrieve defaults from. + /// The globaly configued default options. + public static GraphicsOptions GetDefaultGraphicsOptions(this IImageProcessingContext context) + { + if (context.Properties.TryGetValue(typeof(GraphicsOptions), out var options) && options is GraphicsOptions go) + { + return go; + } + + var configOptions = context.Configuration.GetDefaultGraphicsOptions(); + context.Properties[typeof(GraphicsOptions)] = configOptions; + return configOptions; + } + + /// + /// Gets the default options against the image processing context. + /// + /// The image processing context to retrieve defaults from. + /// The globaly configued default options. + public static GraphicsOptions GetDefaultGraphicsOptions(this Configuration context) + { + if (context.Properties.TryGetValue(typeof(GraphicsOptions), out var options) && options is GraphicsOptions go) + { + return go; + } + + var configOptions = new GraphicsOptions(); + context.Properties[typeof(GraphicsOptions)] = configOptions; + return configOptions; + } + } +} diff --git a/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs b/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs index 2e5919d1e3..5ee3f6483d 100644 --- a/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs +++ b/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Collections.Generic; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors; @@ -15,6 +16,7 @@ namespace SixLabors.ImageSharp.Processing { private readonly bool mutate; private readonly Image source; + private readonly Dictionary properties = new Dictionary(); private Image destination; /// @@ -39,6 +41,9 @@ namespace SixLabors.ImageSharp.Processing /// public Configuration Configuration { get; } + /// + public IDictionary Properties => this.properties; + /// public Image GetResultImage() { diff --git a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs index 4717c09eaf..197dcd3efa 100644 --- a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing Image image, float opacity) { - var options = new GraphicsOptions(); + var options = source.GetDefaultGraphicsOptions(); return source.ApplyProcessor( new DrawImageProcessor( image, @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing image, Point.Empty, colorBlending, - new GraphicsOptions().AlphaCompositionMode, + source.GetDefaultGraphicsOptions().AlphaCompositionMode, opacity)); /// @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Processing Point location, float opacity) { - var options = new GraphicsOptions(); + var options = source.GetDefaultGraphicsOptions(); return source.ApplyProcessor( new DrawImageProcessor( image, @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.Processing image, location, colorBlending, - new GraphicsOptions().AlphaCompositionMode, + source.GetDefaultGraphicsOptions().AlphaCompositionMode, opacity)); /// diff --git a/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs index 84b11c5e71..b46f53cf6a 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Processing.Processors.Filters; @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Lomograph(this IImageProcessingContext source) - => source.ApplyProcessor(new LomographProcessor()); + => source.ApplyProcessor(new LomographProcessor(source.GetDefaultGraphicsOptions())); /// /// Alters the colors of the image recreating an old Lomograph camera effect. @@ -28,6 +28,6 @@ namespace SixLabors.ImageSharp.Processing /// /// The to allow chaining of operations. public static IImageProcessingContext Lomograph(this IImageProcessingContext source, Rectangle rectangle) - => source.ApplyProcessor(new LomographProcessor(), rectangle); + => source.ApplyProcessor(new LomographProcessor(source.GetDefaultGraphicsOptions()), rectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs index 94ced7108d..4e216b4f78 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Processing.Processors.Filters; @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Polaroid(this IImageProcessingContext source) - => source.ApplyProcessor(new PolaroidProcessor()); + => source.ApplyProcessor(new PolaroidProcessor(source.GetDefaultGraphicsOptions())); /// /// Alters the colors of the image recreating an old Polaroid camera effect. @@ -28,6 +28,6 @@ namespace SixLabors.ImageSharp.Processing /// /// The to allow chaining of operations. public static IImageProcessingContext Polaroid(this IImageProcessingContext source, Rectangle rectangle) - => source.ApplyProcessor(new PolaroidProcessor(), rectangle); + => source.ApplyProcessor(new PolaroidProcessor(source.GetDefaultGraphicsOptions()), rectangle); } } diff --git a/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs index d068ba10b5..ced37091ee 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing /// The color to set as the background. /// The to allow chaining of operations. public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, Color color) => - BackgroundColor(source, new GraphicsOptions(), color); + BackgroundColor(source, source.GetDefaultGraphicsOptions(), color); /// /// Replaces the background color of image with the given one. @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing this IImageProcessingContext source, Color color, Rectangle rectangle) => - BackgroundColor(source, new GraphicsOptions(), color, rectangle); + BackgroundColor(source, source.GetDefaultGraphicsOptions(), color, rectangle); /// /// Replaces the background color of image with the given one. diff --git a/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs index d5114e30ab..63f0651193 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source) => - Glow(source, new GraphicsOptions()); + Glow(source, source.GetDefaultGraphicsOptions()); /// /// Applies a radial glow effect to an image. @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, Color color) { - return Glow(source, new GraphicsOptions(), color); + return Glow(source, source.GetDefaultGraphicsOptions(), color); } /// @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing /// The the radius. /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, float radius) => - Glow(source, new GraphicsOptions(), radius); + Glow(source, source.GetDefaultGraphicsOptions(), radius); /// /// Applies a radial glow effect to an image. @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, Rectangle rectangle) => - source.Glow(new GraphicsOptions(), rectangle); + source.Glow(source.GetDefaultGraphicsOptions(), rectangle); /// /// Applies a radial glow effect to an image. @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing Color color, float radius, Rectangle rectangle) => - source.Glow(new GraphicsOptions(), color, ValueSize.Absolute(radius), rectangle); + source.Glow(source.GetDefaultGraphicsOptions(), color, ValueSize.Absolute(radius), rectangle); /// /// Applies a radial glow effect to an image. diff --git a/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs index 799b30e01e..a3063832af 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source) => - Vignette(source, new GraphicsOptions()); + Vignette(source, source.GetDefaultGraphicsOptions()); /// /// Applies a radial vignette effect to an image. @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Processing /// The color to set as the vignette. /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source, Color color) => - Vignette(source, new GraphicsOptions(), color); + Vignette(source, source.GetDefaultGraphicsOptions(), color); /// /// Applies a radial vignette effect to an image. @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing this IImageProcessingContext source, float radiusX, float radiusY) => - Vignette(source, new GraphicsOptions(), radiusX, radiusY); + Vignette(source, source.GetDefaultGraphicsOptions(), radiusX, radiusY); /// /// Applies a radial vignette effect to an image. @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source, Rectangle rectangle) => - Vignette(source, new GraphicsOptions(), rectangle); + Vignette(source, source.GetDefaultGraphicsOptions(), rectangle); /// /// Applies a radial vignette effect to an image. @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing float radiusX, float radiusY, Rectangle rectangle) => - source.Vignette(new GraphicsOptions(), color, radiusX, radiusY, rectangle); + source.Vignette(source.GetDefaultGraphicsOptions(), color, radiusX, radiusY, rectangle); /// /// Applies a radial vignette effect to an image. diff --git a/src/ImageSharp/Processing/IImageProcessingContext.cs b/src/ImageSharp/Processing/IImageProcessingContext.cs index 8b57a289d4..cb39766a94 100644 --- a/src/ImageSharp/Processing/IImageProcessingContext.cs +++ b/src/ImageSharp/Processing/IImageProcessingContext.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Collections.Generic; using SixLabors.ImageSharp.Processing.Processors; namespace SixLabors.ImageSharp.Processing @@ -15,6 +16,12 @@ namespace SixLabors.ImageSharp.Processing /// Configuration Configuration { get; } + /// + /// Gets a set of properties for the Image Processing Context. + /// + /// This can be used for storing global settings and defaults to be accessable to processors. + IDictionary Properties { get; } + /// /// Gets the image dimensions at the current point in the processing pipeline. /// diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs index 3c150d7ebf..bb6ea51c12 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs @@ -11,11 +11,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters /// /// Initializes a new instance of the class. /// - public LomographProcessor() + /// Graphics options to use within the processor. + public LomographProcessor(GraphicsOptions graphicsOptions) : base(KnownFilterMatrices.LomographFilter) { + this.GraphicsOptions = graphicsOptions; } + /// + /// Gets the options effecting blending and composition + /// + public GraphicsOptions GraphicsOptions { get; } + /// public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) => new LomographProcessor(configuration, this, source, sourceRectangle); diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs index 5a19b78516..0706e9fc8d 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs @@ -13,6 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters where TPixel : unmanaged, IPixel { private static readonly Color VeryDarkGreen = Color.FromRgba(0, 10, 0, 255); + private readonly LomographProcessor definition; /// /// Initializes a new instance of the class. @@ -24,12 +25,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters public LomographProcessor(Configuration configuration, LomographProcessor definition, Image source, Rectangle sourceRectangle) : base(configuration, definition, source, sourceRectangle) { + this.definition = definition; } /// protected override void AfterImageApply() { - new VignetteProcessor(VeryDarkGreen).Execute(this.Configuration, this.Source, this.SourceRectangle); + new VignetteProcessor(this.definition.GraphicsOptions, VeryDarkGreen).Execute(this.Configuration, this.Source, this.SourceRectangle); base.AfterImageApply(); } } diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs index a5cf268625..965a35be15 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs @@ -11,11 +11,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters /// /// Initializes a new instance of the class. /// - public PolaroidProcessor() + /// Graphics options to use within the processor. + public PolaroidProcessor(GraphicsOptions graphicsOptions) : base(KnownFilterMatrices.PolaroidFilter) { + this.GraphicsOptions = graphicsOptions; } + /// + /// Gets the options effecting blending and composition + /// + public GraphicsOptions GraphicsOptions { get; } + /// public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) => new PolaroidProcessor(configuration, this, source, sourceRectangle); diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs index 9f547be1c9..470d553c2c 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs @@ -14,6 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters { private static readonly Color LightOrange = Color.FromRgba(255, 153, 102, 128); private static readonly Color VeryDarkOrange = Color.FromRgb(102, 34, 0); + private readonly PolaroidProcessor definition; /// /// Initializes a new instance of the class. @@ -25,13 +26,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters public PolaroidProcessor(Configuration configuration, PolaroidProcessor definition, Image source, Rectangle sourceRectangle) : base(configuration, definition, source, sourceRectangle) { + this.definition = definition; } /// protected override void AfterImageApply() { - new VignetteProcessor(VeryDarkOrange).Execute(this.Configuration, this.Source, this.SourceRectangle); - new GlowProcessor(LightOrange, this.Source.Width / 4F).Execute(this.Configuration, this.Source, this.SourceRectangle); + new VignetteProcessor(this.definition.GraphicsOptions, VeryDarkOrange).Execute(this.Configuration, this.Source, this.SourceRectangle); + new GlowProcessor(this.definition.GraphicsOptions, LightOrange, this.Source.Width / 4F).Execute(this.Configuration, this.Source, this.SourceRectangle); base.AfterImageApply(); } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 87e93ca215..5e0d1cbf7e 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -10,15 +10,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays /// public sealed class GlowProcessor : IImageProcessor { - /// - /// Initializes a new instance of the class. - /// - /// The color or the glow. - public GlowProcessor(Color color) - : this(color, 0) - { - } - /// /// Initializes a new instance of the class. /// @@ -29,16 +20,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays { } - /// - /// Initializes a new instance of the class. - /// - /// The color or the glow. - /// The radius of the glow. - internal GlowProcessor(Color color, ValueSize radius) - : this(new GraphicsOptions(), color, radius) - { - } - /// /// Initializes a new instance of the class. /// diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 5654eccfa4..3b16f8bc85 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -10,15 +10,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays /// public sealed class VignetteProcessor : IImageProcessor { - /// - /// Initializes a new instance of the class. - /// - /// The color of the vignette. - public VignetteProcessor(Color color) - : this(new GraphicsOptions(), color) - { - } - /// /// Initializes a new instance of the class. /// diff --git a/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs b/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs index 3f11b46310..cd4d782792 100644 --- a/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs +++ b/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs @@ -56,6 +56,8 @@ namespace SixLabors.ImageSharp.Tests.Processing public Configuration Configuration { get; } + public IDictionary Properties { get; } = new Dictionary(); + public Image GetResultImage() { return this.Source; From 0ab64c2f895adce9db275192aecb4328693f4706 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 18 Apr 2020 16:34:06 +0100 Subject: [PATCH 129/213] Add some unit tests to verify usage of default graphics options --- .../GraphicOptionsDefaultsExtensions.cs | 7 +- .../Drawing/DrawImageExtensionsTests.cs | 83 ++++++++++++ .../GraphicOptionsDefaultsExtensionsTests.cs | 128 ++++++++++++++++++ .../BaseImageOperationsExtensionTest.cs | 1 + .../Processing/Effects/BackgroundColorTest.cs | 10 +- .../Processing/Filters/LomographTest.cs | 6 +- .../Processing/Filters/PolaroidTest.cs | 6 +- .../Processing/Overlays/GlowTest.cs | 10 +- .../Processing/Overlays/VignetteTest.cs | 10 +- 9 files changed, 238 insertions(+), 23 deletions(-) create mode 100644 tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs create mode 100644 tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs diff --git a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs index 3d86a5b0c1..38baf91d37 100644 --- a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs +++ b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp @@ -43,7 +44,9 @@ namespace SixLabors.ImageSharp } var configOptions = context.Configuration.GetDefaultGraphicsOptions(); - context.Properties[typeof(GraphicsOptions)] = configOptions; + + // do not cache the fall back to config into the the processing context + // in case someone want to change the value on the config and expects it re trflow thru return configOptions; } @@ -60,6 +63,8 @@ namespace SixLabors.ImageSharp } var configOptions = new GraphicsOptions(); + + // capture the fallback so the same instance will always be returned in case its mutated context.Properties[typeof(GraphicsOptions)] = configOptions; return configOptions; } diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs new file mode 100644 index 0000000000..3f90412ae9 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs @@ -0,0 +1,83 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Linq; +using Moq; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Drawing; +using SixLabors.ImageSharp.Tests.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Drawing +{ + public class DrawImageExtensionsTests : BaseImageOperationsExtensionTest + { + + [Fact] + public void DrawImage_OpacityOnly_VerifyGraphicOptionsTakenFromContext() + { + // non-default values as we cant easly defect usage otherwise + this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor; + this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; + + this.operations.DrawImage(null, 0.5f); + var dip = this.Verify(); + + Assert.Equal(0.5, dip.Opacity); + Assert.Equal(this.options.AlphaCompositionMode, dip.AlphaCompositionMode); + Assert.Equal(this.options.ColorBlendingMode, dip.ColorBlendingMode); + } + + [Fact] + public void DrawImage_OpacityAndBlending_VerifyGraphicOptionsTakenFromContext() + { + // non-default values as we cant easly defect usage otherwise + this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor; + this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; + + this.operations.DrawImage(null, PixelColorBlendingMode.Multiply, 0.5f); + var dip = this.Verify(); + + Assert.Equal(0.5, dip.Opacity); + Assert.Equal(this.options.AlphaCompositionMode, dip.AlphaCompositionMode); + Assert.Equal(PixelColorBlendingMode.Multiply, dip.ColorBlendingMode); + } + + [Fact] + public void DrawImage_LocationAndOpacity_VerifyGraphicOptionsTakenFromContext() + { + // non-default values as we cant easly defect usage otherwise + this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor; + this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; + + this.operations.DrawImage(null, Point.Empty, 0.5f); + var dip = this.Verify(); + + Assert.Equal(0.5, dip.Opacity); + Assert.Equal(this.options.AlphaCompositionMode, dip.AlphaCompositionMode); + Assert.Equal(this.options.ColorBlendingMode, dip.ColorBlendingMode); + } + + [Fact] + public void DrawImage_LocationAndOpacityAndBlending_VerifyGraphicOptionsTakenFromContext() + { + // non-default values as we cant easly defect usage otherwise + this.options.AlphaCompositionMode = PixelAlphaCompositionMode.Xor; + this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; + + this.operations.DrawImage(null, Point.Empty, PixelColorBlendingMode.Multiply, 0.5f); + var dip = this.Verify(); + + Assert.Equal(0.5, dip.Opacity); + Assert.Equal(this.options.AlphaCompositionMode, dip.AlphaCompositionMode); + Assert.Equal(PixelColorBlendingMode.Multiply, dip.ColorBlendingMode); + } + } +} diff --git a/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs b/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs new file mode 100644 index 0000000000..6707341d26 --- /dev/null +++ b/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs @@ -0,0 +1,128 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.Processing; +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public class GraphicOptionsDefaultsExtensionsTests + { + [Fact] + public void SetDefaultOptionsOnProcessingContext() + { + var option = new GraphicsOptions(); + var config = new Configuration(); + var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); + + context.SetDefaultOptions(option); + + // sets the prop on the processing context not on the configuration + Assert.Equal(option, context.Properties[typeof(GraphicsOptions)]); + Assert.DoesNotContain(typeof(GraphicsOptions), config.Properties.Keys); + } + + [Fact] + public void SetDefaultOptionsOnConfiguration() + { + var option = new GraphicsOptions(); + var config = new Configuration(); + + config.SetDefaultOptions(option); + + Assert.Equal(option, config.Properties[typeof(GraphicsOptions)]); + } + + [Fact] + public void GetDefaultOptionsFromConfiguration_SettingNullThenReturnsNewInstance() + { + var config = new Configuration(); + + var options = config.GetDefaultGraphicsOptions(); + Assert.NotNull(options); + config.SetDefaultOptions((GraphicsOptions)null); + + var options2 = config.GetDefaultGraphicsOptions(); + Assert.NotNull(options2); + + // we set it to null should now be a new instance + Assert.NotEqual(options, options2); + } + + [Fact] + public void GetDefaultOptionsFromConfiguration_IgnoreIncorectlyTypesDictionEntry() + { + var config = new Configuration(); + + config.Properties[typeof(GraphicsOptions)] = "wronge type"; + var options = config.GetDefaultGraphicsOptions(); + Assert.NotNull(options); + Assert.IsType(options); + } + + [Fact] + public void GetDefaultOptionsFromConfiguration_AlwaysReturnsInstance() + { + var config = new Configuration(); + + Assert.DoesNotContain(typeof(GraphicsOptions), config.Properties.Keys); + var options = config.GetDefaultGraphicsOptions(); + Assert.NotNull(options); + } + + [Fact] + public void GetDefaultOptionsFromConfiguration_AlwaysReturnsSameValue() + { + var config = new Configuration(); + + var options = config.GetDefaultGraphicsOptions(); + var options2 = config.GetDefaultGraphicsOptions(); + Assert.Equal(options, options2); + } + + [Fact] + public void GetDefaultOptionsFromProcessingContext_AlwaysReturnsInstance() + { + var config = new Configuration(); + var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); + + var ctxOptions = context.GetDefaultGraphicsOptions(); + Assert.NotNull(ctxOptions); + } + + [Fact] + public void GetDefaultOptionsFromProcessingContext_AlwaysReturnsInstanceEvenIfSetToNull() + { + var config = new Configuration(); + var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); + + context.SetDefaultOptions((GraphicsOptions)null); + var ctxOptions = context.GetDefaultGraphicsOptions(); + Assert.NotNull(ctxOptions); + } + + [Fact] + public void GetDefaultOptionsFromProcessingContext_FallbackToConfigsInstance() + { + var option = new GraphicsOptions(); + var config = new Configuration(); + config.SetDefaultOptions(option); + var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); + + var ctxOptions = context.GetDefaultGraphicsOptions(); + Assert.Equal(option, ctxOptions); + } + + [Fact] + public void GetDefaultOptionsFromProcessingContext_IgnoreIncorectlyTypesDictionEntry() + { + var config = new Configuration(); + var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); + context.Properties[typeof(GraphicsOptions)] = "wronge type"; + var options = context.GetDefaultGraphicsOptions(); + Assert.NotNull(options); + Assert.IsType(options); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs index 82c22245d2..da20401310 100644 --- a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs +++ b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs @@ -25,6 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Processing this.source = new Image(91 + 324, 123 + 56); this.rect = new Rectangle(91, 123, 324, 56); // make this random? this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(this.source.GetConfiguration(), this.source, false); + this.internalOperations.SetDefaultOptions(this.options); this.operations = this.internalOperations; } diff --git a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs index 37bd2e87aa..34b99461d3 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs @@ -10,15 +10,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Effects { public class BackgroundColorTest : BaseImageOperationsExtensionTest { - private static readonly GraphicsOptionsComparer GraphicsOptionsComparer = new GraphicsOptionsComparer(); - [Fact] public void BackgroundColor_amount_BackgroundColorProcessorDefaultsSet() { this.operations.BackgroundColor(Color.BlanchedAlmond); BackgroundColorProcessor processor = this.Verify(); - Assert.Equal(new GraphicsOptions(), processor.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, processor.GraphicsOptions); Assert.Equal(Color.BlanchedAlmond, processor.Color); } @@ -28,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Effects this.operations.BackgroundColor(Color.BlanchedAlmond, this.rect); BackgroundColorProcessor processor = this.Verify(this.rect); - Assert.Equal(new GraphicsOptions(), processor.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, processor.GraphicsOptions); Assert.Equal(Color.BlanchedAlmond, processor.Color); } @@ -38,7 +36,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Effects this.operations.BackgroundColor(this.options, Color.BlanchedAlmond); BackgroundColorProcessor processor = this.Verify(); - Assert.Equal(this.options, processor.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, processor.GraphicsOptions); Assert.Equal(Color.BlanchedAlmond, processor.Color); } @@ -48,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Effects this.operations.BackgroundColor(this.options, Color.BlanchedAlmond, this.rect); BackgroundColorProcessor processor = this.Verify(this.rect); - Assert.Equal(this.options, processor.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, processor.GraphicsOptions); Assert.Equal(Color.BlanchedAlmond, processor.Color); } } diff --git a/tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs b/tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs index 65e04fbcc7..6cb38e2fe9 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs @@ -16,14 +16,16 @@ namespace SixLabors.ImageSharp.Tests public void Lomograph_amount_LomographProcessorDefaultsSet() { this.operations.Lomograph(); - this.Verify(); + var processor = this.Verify(); + Assert.Equal(processor.GraphicsOptions, this.options); } [Fact] public void Lomograph_amount_rect_LomographProcessorDefaultsSet() { this.operations.Lomograph(this.rect); - this.Verify(this.rect); + var processor = this.Verify(this.rect); + Assert.Equal(processor.GraphicsOptions, this.options); } } } diff --git a/tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs b/tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs index c3e2c3c502..346df03799 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs @@ -14,14 +14,16 @@ namespace SixLabors.ImageSharp.Tests.Processing.Filters public void Polaroid_amount_PolaroidProcessorDefaultsSet() { this.operations.Polaroid(); - this.Verify(); + var processor = this.Verify(); + Assert.Equal(processor.GraphicsOptions, this.options); } [Fact] public void Polaroid_amount_rect_PolaroidProcessorDefaultsSet() { this.operations.Polaroid(this.rect); - this.Verify(this.rect); + var processor = this.Verify(this.rect); + Assert.Equal(processor.GraphicsOptions, this.options); } } } diff --git a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs index ea000ae2a6..0336b231b5 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs @@ -11,15 +11,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays { public class GlowTest : BaseImageOperationsExtensionTest { - private static readonly GraphicsOptionsComparer GraphicsOptionsComparer = new GraphicsOptionsComparer(); - [Fact] public void Glow_GlowProcessorWithDefaultValues() { this.operations.Glow(); GlowProcessor p = this.Verify(); - Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, p.GraphicsOptions); Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } @@ -30,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays this.operations.Glow(Color.Aquamarine); GlowProcessor p = this.Verify(); - Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, p.GraphicsOptions); Assert.Equal(Color.Aquamarine, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } @@ -41,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays this.operations.Glow(3.5f); GlowProcessor p = this.Verify(); - Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, p.GraphicsOptions); Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.Absolute(3.5f), p.Radius); } @@ -53,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays this.operations.Glow(rect); GlowProcessor p = this.Verify(rect); - Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, p.GraphicsOptions); Assert.Equal(Color.Black, p.GlowColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.Radius); } diff --git a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs index 8e5eb72075..5d41c58cea 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs @@ -10,15 +10,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays { public class VignetteTest : BaseImageOperationsExtensionTest { - private static readonly GraphicsOptionsComparer GraphicsOptionsComparer = new GraphicsOptionsComparer(); - [Fact] public void Vignette_VignetteProcessorWithDefaultValues() { this.operations.Vignette(); VignetteProcessor p = this.Verify(); - Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, p.GraphicsOptions); Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); @@ -30,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays this.operations.Vignette(Color.Aquamarine); VignetteProcessor p = this.Verify(); - Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, p.GraphicsOptions); Assert.Equal(Color.Aquamarine, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); @@ -42,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays this.operations.Vignette(3.5f, 12123f); VignetteProcessor p = this.Verify(); - Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, p.GraphicsOptions); Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.Absolute(3.5f), p.RadiusX); Assert.Equal(ValueSize.Absolute(12123f), p.RadiusY); @@ -55,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Overlays this.operations.Vignette(rect); VignetteProcessor p = this.Verify(rect); - Assert.Equal(new GraphicsOptions(), p.GraphicsOptions, GraphicsOptionsComparer); + Assert.Equal(this.options, p.GraphicsOptions); Assert.Equal(Color.Black, p.VignetteColor); Assert.Equal(ValueSize.PercentageOfWidth(.5f), p.RadiusX); Assert.Equal(ValueSize.PercentageOfHeight(.5f), p.RadiusY); From 5df21ad69a457f00069288c4e2e325dca8440226 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 18 Apr 2020 16:47:09 +0100 Subject: [PATCH 130/213] Add options builder extension --- .../GraphicOptionsDefaultsExtensions.cs | 26 +++++++++- .../GraphicOptionsDefaultsExtensionsTests.cs | 50 +++++++++++++++++-- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs index 38baf91d37..45e444ffe3 100644 --- a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs +++ b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs @@ -11,6 +11,30 @@ namespace SixLabors.ImageSharp /// public static class GraphicOptionsDefaultsExtensions { + /// + /// Sets the default options against the image processing context. + /// + /// The image processing context to store default against. + /// The action to update instance of the default options used. + public static void SetDefaultOptions(this IImageProcessingContext context, Action optionsBuilder) + { + var cloned = context.GetDefaultGraphicsOptions().DeepClone(); + optionsBuilder(cloned); + context.Properties[typeof(GraphicsOptions)] = cloned; + } + + /// + /// Sets the default options against the configuration. + /// + /// The image processing context to store default against. + /// The default options to use. + public static void SetDefaultGraphicsOptions(this Configuration context, Action optionsBuilder) + { + var cloned = context.GetDefaultGraphicsOptions().DeepClone(); + optionsBuilder(cloned); + context.Properties[typeof(GraphicsOptions)] = cloned; + } + /// /// Sets the default options against the image processing context. /// @@ -26,7 +50,7 @@ namespace SixLabors.ImageSharp /// /// The image processing context to store default against. /// The default options to use. - public static void SetDefaultOptions(this Configuration context, GraphicsOptions options) + public static void SetDefaultGraphicsOptions(this Configuration context, GraphicsOptions options) { context.Properties[typeof(GraphicsOptions)] = options; } diff --git a/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs b/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs index 6707341d26..4b0d7a62d5 100644 --- a/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs +++ b/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs @@ -3,6 +3,7 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; namespace SixLabors.ImageSharp.Tests @@ -23,17 +24,60 @@ namespace SixLabors.ImageSharp.Tests Assert.DoesNotContain(typeof(GraphicsOptions), config.Properties.Keys); } + [Fact] + public void UpdateDefaultOptionsOnProcessingContext_AlwaysNewInstance() + { + var option = new GraphicsOptions() + { + BlendPercentage = 0.9f + }; + var config = new Configuration(); + var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); + context.SetDefaultOptions(option); + + context.SetDefaultOptions(o => + { + Assert.Equal(0.9f, o.BlendPercentage); // has origional values + o.BlendPercentage = 0.4f; + }); + + var returnedOption = context.GetDefaultGraphicsOptions(); + Assert.Equal(0.4f, returnedOption.BlendPercentage); + Assert.Equal(0.9f, option.BlendPercentage); // hasn't been mutated + } + [Fact] public void SetDefaultOptionsOnConfiguration() { var option = new GraphicsOptions(); var config = new Configuration(); - config.SetDefaultOptions(option); + config.SetDefaultGraphicsOptions(option); Assert.Equal(option, config.Properties[typeof(GraphicsOptions)]); } + [Fact] + public void UpdateDefaultOptionsOnConfiguration_AlwaysNewInstance() + { + var option = new GraphicsOptions() + { + BlendPercentage = 0.9f + }; + var config = new Configuration(); + config.SetDefaultGraphicsOptions(option); + + config.SetDefaultGraphicsOptions(o => + { + Assert.Equal(0.9f, o.BlendPercentage); // has origional values + o.BlendPercentage = 0.4f; + }); + + var returnedOption = config.GetDefaultGraphicsOptions(); + Assert.Equal(0.4f, returnedOption.BlendPercentage); + Assert.Equal(0.9f, option.BlendPercentage); // hasn't been mutated + } + [Fact] public void GetDefaultOptionsFromConfiguration_SettingNullThenReturnsNewInstance() { @@ -41,7 +85,7 @@ namespace SixLabors.ImageSharp.Tests var options = config.GetDefaultGraphicsOptions(); Assert.NotNull(options); - config.SetDefaultOptions((GraphicsOptions)null); + config.SetDefaultGraphicsOptions((GraphicsOptions)null); var options2 = config.GetDefaultGraphicsOptions(); Assert.NotNull(options2); @@ -107,7 +151,7 @@ namespace SixLabors.ImageSharp.Tests { var option = new GraphicsOptions(); var config = new Configuration(); - config.SetDefaultOptions(option); + config.SetDefaultGraphicsOptions(option); var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); var ctxOptions = context.GetDefaultGraphicsOptions(); From 406573cb8ed2d2c833fa234f13647057f18505ba Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 18 Apr 2020 16:54:33 +0100 Subject: [PATCH 131/213] Update ImageExtensions.cs --- src/ImageSharp/ImageExtensions.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 0bdbcc4ab3..62ac449b72 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -103,14 +103,18 @@ namespace SixLabors.ImageSharp /// /// Returns a Base64 encoded string from the given image. + /// The result is prepended with a Data URI + /// + /// + /// For example: + /// + /// + /// /// - /// - /// The pixel format. /// The source image /// The format. /// The - public static string ToBase64String(this Image source, IImageFormat format) - where TPixel : unmanaged, IPixel + public static string ToBase64String(this Image source, IImageFormat format) { using var stream = new MemoryStream(); source.Save(stream, format); From f1a99e70e0e2ff9e7a64095f3742305502372dba Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 18 Apr 2020 18:03:01 +0200 Subject: [PATCH 132/213] Add SetDateTimeValue which makes sure the formatting will be as specified in the spec --- .../Metadata/Profiles/IPTC/IptcProfile.cs | 22 ++++++++++ .../Metadata/Profiles/IPTC/IptcTag.cs | 22 ++++------ .../Profiles/IPTC/IptcTagExtensions.cs | 43 ++++++++++++++++++- .../Metadata/Profiles/IPTC/IptcValue.cs | 6 +++ .../Profiles/IPTC/IptcProfileTests.cs | 43 ++++++++++++++++++- 5 files changed, 120 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index b86f6dff2d..cd3c8eb931 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -174,6 +174,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc public void SetValue(IptcTag tag, Encoding encoding, string value, bool strict = true) { Guard.NotNull(encoding, nameof(encoding)); + Guard.NotNull(value, nameof(value)); if (!tag.IsRepeatable()) { @@ -192,6 +193,27 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc this.values.Add(new IptcValue(tag, encoding, value, strict)); } + /// + /// Makes sure the datetime is formatted according to the iptc specification. + /// A date will be formatted as CCYYMMDD. + /// A time value will be formatted as HHMMSS±HHMM. + /// + /// The tag of the iptc value. + /// The datetime. + public void SetDateTimeValue(IptcTag tag, DateTime dateTime) + { + if (!tag.IsDate() && !tag.IsTime()) + { + throw new ArgumentException("iptc tag is not a time or date type"); + } + + var formattedDate = tag.IsDate() + ? dateTime.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture) + : dateTime.ToString("HHmmsszzzz", System.Globalization.CultureInfo.InvariantCulture).Replace(":", string.Empty); + + this.SetValue(tag, Encoding.UTF8, formattedDate); + } + /// /// Sets the value of the specified tag. /// diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs index 135c41e51f..62f74386eb 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs @@ -86,30 +86,28 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// /// Release date. Format should be CCYYMMDD, - /// e.g. "19890317" indicates data for release on 17 March 1989. + /// e.g. "19890317" for the 17 March 1989. /// Not repeatable, max length is 8. /// ReleaseDate = 30, /// /// Release time. Format should be HHMMSS±HHMM, - /// e.g. "090000-0500" indicates object for use after 0900 in - /// New York (five hours behind UTC) + /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC). /// Not repeatable, max length is 11. /// ReleaseTime = 35, /// /// Expiration date. Format should be CCYYMMDD, - /// e.g. "19890317" indicates data for release on 17 March 1989. + /// e.g. "19890317" for the 17 March 1989. /// Not repeatable, max length is 8. /// ExpirationDate = 37, /// /// Expiration time. Format should be HHMMSS±HHMM, - /// e.g. "090000-0500" indicates object for use after 0900 in - /// New York (five hours behind UTC) + /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC). /// Not repeatable, max length is 11. /// ExpirationTime = 38, @@ -131,7 +129,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// /// Reference date. Format should be CCYYMMDD, - /// e.g. "19890317" indicates data for release on 17 March 1989. + /// e.g. "19890317" for the 17 March 1989. /// Not repeatable, max length is 8. /// ReferenceDate = 47, @@ -143,30 +141,28 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// /// Created date. Format should be CCYYMMDD, - /// e.g. "19890317" indicates data for release on 17 March 1989. + /// e.g. "19890317" for the 17 March 1989. /// Not repeatable, max length is 8. /// CreatedDate = 55, /// /// Created time. Format should be HHMMSS±HHMM, - /// e.g. "090000-0500" indicates object for use after 0900 in - /// New York (five hours behind UTC) + /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC). /// Not repeatable, max length is 11. /// CreatedTime = 60, /// /// Digital creation date. Format should be CCYYMMDD, - /// e.g. "19890317" indicates data for release on 17 March 1989. + /// e.g. "19890317" for the 17 March 1989. /// Not repeatable, max length is 8. /// DigitalCreationDate = 62, /// /// Digital creation time. Format should be HHMMSS±HHMM, - /// e.g. "090000-0500" indicates object for use after 0900 in - /// New York (five hours behind UTC) + /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC). /// Not repeatable, max length is 11. /// DigitalCreationTime = 63, diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs index 88d463767d..6b39769a7f 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc @@ -117,5 +117,46 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc return true; } } + + /// + /// Determines if the tag is a datetime tag which needs to be formatted as CCYYMMDD. + /// + /// The tag to check. + /// True, if its a datetime tag. + public static bool IsDate(this IptcTag tag) + { + switch (tag) + { + case IptcTag.CreatedDate: + case IptcTag.DigitalCreationDate: + case IptcTag.ExpirationDate: + case IptcTag.ReferenceDate: + case IptcTag.ReleaseDate: + return true; + + default: + return false; + } + } + + /// + /// Determines if the tag is a time tag which need to be formatted as HHMMSS±HHMM. + /// + /// The tag to check. + /// True, if its a time tag. + public static bool IsTime(this IptcTag tag) + { + switch (tag) + { + case IptcTag.CreatedTime: + case IptcTag.DigitalCreationTime: + case IptcTag.ExpirationTime: + case IptcTag.ReleaseTime: + return true; + + default: + return false; + } + } } } diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs index 2c2cf59954..8e804353c6 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs @@ -103,6 +103,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { var cappedValue = value.Substring(0, maxLength); valueBytes = this.encoding.GetBytes(cappedValue); + + // It is still possible that the bytes of the string exceed the limit. + if (valueBytes.Length > maxLength) + { + throw new ArgumentException($"The iptc value exceeds the limit of {maxLength} bytes for the tag {this.Tag}"); + } } else { diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index 321c7fe5c0..9d5db439a7 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC { private static JpegDecoder JpegDecoder => new JpegDecoder() { IgnoreMetadata = false }; - public static IEnumerable allIptcTags() + public static IEnumerable AllIptcTags() { foreach (object tag in Enum.GetValues(typeof(IptcTag))) { @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC } [Theory] - [MemberData("allIptcTags")] + [MemberData("AllIptcTags")] public void IptcProfile_SetValue_WithStrictOption_Works(IptcTag tag) { // arrange @@ -41,6 +41,45 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC Assert.Equal(expectedLength, actual.Value.Length); } + [Theory] + [InlineData(IptcTag.DigitalCreationDate)] + [InlineData(IptcTag.ExpirationDate)] + [InlineData(IptcTag.CreatedDate)] + [InlineData(IptcTag.ReferenceDate)] + [InlineData(IptcTag.ReleaseDate)] + public void IptcProfile_SetDateValue_Works(IptcTag tag) + { + // arrange + var profile = new IptcProfile(); + var datetime = new DateTime(1994, 3, 17); + + // act + profile.SetDateTimeValue(tag, datetime); + + // assert + IptcValue actual = profile.GetValues(tag).First(); + Assert.Equal("19940317", actual.Value); + } + + [Theory] + [InlineData(IptcTag.CreatedTime)] + [InlineData(IptcTag.DigitalCreationTime)] + [InlineData(IptcTag.ExpirationTime)] + [InlineData(IptcTag.ReleaseTime)] + public void IptcProfile_SetTimeValue_Works(IptcTag tag) + { + // arrange + var profile = new IptcProfile(); + DateTime datetime = new DateTimeOffset(new DateTime(1994, 3, 17, 14, 15, 16), new TimeSpan(1, 0, 0)).DateTime; + + // act + profile.SetDateTimeValue(tag, datetime); + + // assert + IptcValue actual = profile.GetValues(tag).First(); + Assert.Equal("141516+0100", actual.Value); + } + [Theory] [WithFile(TestImages.Jpeg.Baseline.Iptc, PixelTypes.Rgba32)] public void ReadIptcMetadata_Works(TestImageProvider provider) From 4a70056a2b38c7b728c10f6b04066991bef2db7b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 19 Apr 2020 10:30:42 +0200 Subject: [PATCH 133/213] SetDateTimeValue now uses DateTimeOffset --- src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs | 9 +++++---- .../Metadata/Profiles/IPTC/IptcProfileTests.cs | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index cd3c8eb931..a46d2745ff 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -199,8 +199,8 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// A time value will be formatted as HHMMSS±HHMM. /// /// The tag of the iptc value. - /// The datetime. - public void SetDateTimeValue(IptcTag tag, DateTime dateTime) + /// The datetime. + public void SetDateTimeValue(IptcTag tag, DateTimeOffset dateTimeOffset) { if (!tag.IsDate() && !tag.IsTime()) { @@ -208,8 +208,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc } var formattedDate = tag.IsDate() - ? dateTime.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture) - : dateTime.ToString("HHmmsszzzz", System.Globalization.CultureInfo.InvariantCulture).Replace(":", string.Empty); + ? dateTimeOffset.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture) + : dateTimeOffset.ToString("HHmmsszzzz", System.Globalization.CultureInfo.InvariantCulture) + .Replace(":", string.Empty); this.SetValue(tag, Encoding.UTF8, formattedDate); } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index 9d5db439a7..d9f44cef9c 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC { // arrange var profile = new IptcProfile(); - var datetime = new DateTime(1994, 3, 17); + var datetime = new DateTimeOffset(new DateTime(1994, 3, 17)); // act profile.SetDateTimeValue(tag, datetime); @@ -70,14 +70,15 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC { // arrange var profile = new IptcProfile(); - DateTime datetime = new DateTimeOffset(new DateTime(1994, 3, 17, 14, 15, 16), new TimeSpan(1, 0, 0)).DateTime; + var dateTimeUtc = new DateTime(1994, 3, 17, 14, 15, 16, DateTimeKind.Utc); + DateTimeOffset dateTimeOffset = new DateTimeOffset(dateTimeUtc).ToOffset(TimeSpan.FromHours(2)); // act - profile.SetDateTimeValue(tag, datetime); + profile.SetDateTimeValue(tag, dateTimeOffset); // assert IptcValue actual = profile.GetValues(tag).First(); - Assert.Equal("141516+0100", actual.Value); + Assert.Equal("161516+0200", actual.Value); } [Theory] From 12c3537e562dbc2ade9d905d699f22e3e7161ff3 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 19 Apr 2020 11:17:05 +0200 Subject: [PATCH 134/213] Use tag for examples --- .../Metadata/Profiles/IPTC/IptcProfile.cs | 7 ++- .../Metadata/Profiles/IPTC/IptcTag.cs | 58 +++++++++++++------ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index a46d2745ff..b46eee0fd9 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -195,8 +195,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// /// Makes sure the datetime is formatted according to the iptc specification. - /// A date will be formatted as CCYYMMDD. - /// A time value will be formatted as HHMMSS±HHMM. + /// + /// A date will be formatted as CCYYMMDD, e.g. "19890317" for 17 March 1989. + /// A time value will be formatted as HHMMSS±HHMM, e.g. "090000+0200" for 9 o'clock Berlin time, + /// two hours ahead of UTC. + /// /// /// The tag of the iptc value. /// The datetime. diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs index 62f74386eb..70a90aa108 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs @@ -85,30 +85,40 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc LocationName = 27, /// - /// Release date. Format should be CCYYMMDD, - /// e.g. "19890317" for the 17 March 1989. + /// Release date. Format should be CCYYMMDD. /// Not repeatable, max length is 8. + /// + /// A date will be formatted as CCYYMMDD, e.g. "19890317" for 17 March 1989. + /// /// ReleaseDate = 30, /// - /// Release time. Format should be HHMMSS±HHMM, - /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC). + /// Release time. Format should be HHMMSS±HHMM. /// Not repeatable, max length is 11. + /// + /// A time value will be formatted as HHMMSS±HHMM, e.g. "090000+0200" for 9 o'clock Berlin time, + /// two hours ahead of UTC. + /// /// ReleaseTime = 35, /// - /// Expiration date. Format should be CCYYMMDD, - /// e.g. "19890317" for the 17 March 1989. + /// Expiration date. Format should be CCYYMMDD. /// Not repeatable, max length is 8. + /// + /// A date will be formatted as CCYYMMDD, e.g. "19890317" for 17 March 1989. + /// /// ExpirationDate = 37, /// - /// Expiration time. Format should be HHMMSS±HHMM, - /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC). + /// Expiration time. Format should be HHMMSS±HHMM. /// Not repeatable, max length is 11. + /// + /// A time value will be formatted as HHMMSS±HHMM, e.g. "090000+0200" for 9 o'clock Berlin time, + /// two hours ahead of UTC. + /// /// ExpirationTime = 38, @@ -128,9 +138,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc ReferenceService = 45, /// - /// Reference date. Format should be CCYYMMDD, - /// e.g. "19890317" for the 17 March 1989. + /// Reference date. Format should be CCYYMMDD. /// Not repeatable, max length is 8. + /// + /// A date will be formatted as CCYYMMDD, e.g. "19890317" for 17 March 1989. + /// /// ReferenceDate = 47, @@ -140,30 +152,40 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc ReferenceNumber = 50, /// - /// Created date. Format should be CCYYMMDD, - /// e.g. "19890317" for the 17 March 1989. + /// Created date. Format should be CCYYMMDD. /// Not repeatable, max length is 8. + /// + /// A date will be formatted as CCYYMMDD, e.g. "19890317" for 17 March 1989. + /// /// CreatedDate = 55, /// - /// Created time. Format should be HHMMSS±HHMM, - /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC). + /// Created time. Format should be HHMMSS±HHMM. /// Not repeatable, max length is 11. + /// + /// A time value will be formatted as HHMMSS±HHMM, e.g. "090000+0200" for 9 o'clock Berlin time, + /// two hours ahead of UTC. + /// /// CreatedTime = 60, /// - /// Digital creation date. Format should be CCYYMMDD, - /// e.g. "19890317" for the 17 March 1989. + /// Digital creation date. Format should be CCYYMMDD. /// Not repeatable, max length is 8. + /// + /// A date will be formatted as CCYYMMDD, e.g. "19890317" for 17 March 1989. + /// /// DigitalCreationDate = 62, /// - /// Digital creation time. Format should be HHMMSS±HHMM, - /// e.g. "090000-0500" for 9 o'clock New York time (five hours behind UTC). + /// Digital creation time. Format should be HHMMSS±HHMM. /// Not repeatable, max length is 11. + /// + /// A time value will be formatted as HHMMSS±HHMM, e.g. "090000+0200" for 9 o'clock Berlin time, + /// two hours ahead of UTC. + /// /// DigitalCreationTime = 63, From f0e5379ba614c3bd598575bb22d2bf883d01ee42 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 19 Apr 2020 14:01:00 +0100 Subject: [PATCH 135/213] Update license and readme. --- LICENSE | 862 +++++++++++++++++++++++++++++++++++++++++------------- README.md | 156 ++-------- 2 files changed, 682 insertions(+), 336 deletions(-) diff --git a/LICENSE b/LICENSE index 2eeb57968e..0ad25db4bd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,661 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2018 Six Labors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md index 1e52039568..820ceb11bf 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ SixLabors.ImageSharp [![Build Status](https://img.shields.io/github/workflow/status/SixLabors/ImageSharp/Build/master)](https://github.com/SixLabors/ImageSharp/actions) [![Code coverage](https://codecov.io/gh/SixLabors/ImageSharp/branch/master/graph/badge.svg)](https://codecov.io/gh/SixLabors/ImageSharp) -[![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/SixLabors/ImageSharp/master/LICENSE) +[![License: AGPL v3](https://img.shields.io/badge/license-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ImageSharp/General?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=flat&logo=twitter)](https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&url=https%3a%2f%2fgithub.com%2fSixLabors%2fImageSharp&via=sixlabors) [![OpenCollective](https://opencollective.com/imagesharp/backers/badge.svg)](#backers) @@ -20,83 +20,41 @@ SixLabors.ImageSharp ### **ImageSharp** is a new, fully featured, fully managed, cross-platform, 2D graphics API. -Designed to democratize image processing, ImageSharp brings you an incredibly powerful yet beautifully simple API. +ImageSharp is a new, fully featured, fully managed, cross-platform, 2D graphics library. Designed to simplify image processing, ImageSharp brings you an incredibly powerful yet beautifully simple API. -Compared to `System.Drawing` we have been able to develop something much more flexible, easier to code against, and much, much less prone to memory leaks. Gone are system-wide process-locks; ImageSharp images are thread-safe and fully supported in web environments. +ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of addtional operations. -Built against .NET Standard 1.3, ImageSharp can be used in device, cloud, and embedded/IoT scenarios. +Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. -### Documentation -For all SixLabors projects, including ImageSharp: -https://sixlabors.github.io/docs/ - -### Installation -Install stable releases via Nuget; development releases are available via MyGet. +### License + +- ImageSharp is licensed under the [GNU Affero General Public License v3](https://www.gnu.org/licenses/agpl-3.0) +- In addition to this license, ImageSharp is offered under a commercial license. +Please visit https://sixlabors.com/pricing for details. +- Open Source projects who whave taken a dependency on ImageSharp prior to adoption of the AGPLv3 license are permitted to use ImageSharp (including all future versions) under the previous [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). -| Package Name | Release (NuGet) | Nightly (MyGet) | -|--------------------------------|-----------------|-----------------| -| `SixLabors.ImageSharp` | [![NuGet](https://img.shields.io/nuget/v/SixLabors.ImageSharp.svg)](https://www.nuget.org/packages/SixLabors.ImageSharp/) | [![MyGet](https://img.shields.io/myget/sixlabors/v/SixLabors.ImageSharp.svg)](https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp) | - -### Packages +### Documentation -The **ImageSharp** library is made up of multiple packages: -- **SixLabors.ImageSharp** - - Contains the generic `Image` class, PixelFormats, Primitives, Configuration, and other core functionality - - The `IImageFormat` interface, Jpeg, Png, Bmp, and Gif formats - - Transform methods like Resize, Crop, Skew, Rotate - anything that alters the dimensions of the image - - Non-transform methods like Gaussian Blur, Pixelate, Edge Detection - anything that maintains the original image dimensions +- [Detailed documentation](https://sixlabors.github.io/docs/) for the ImageSharp API is available. This includes additional conceptual documentation to help you get started. +- Our [Samples Repository](https://github.com/SixLabors/Samples/tree/master/ImageSharp) is also available containing buildable code samples demonstrating commmon activities. ### Questions? -- Do you have questions? We are happy to help! Please [join our gitter channel](https://gitter.im/ImageSharp/General), or ask them on [stackoverflow](https://stackoverflow.com) using the `ImageSharp` tag. **Do not** open issues for questions! +- Do you have questions? We are happy to help! Please [join our Gitter channel](https://gitter.im/ImageSharp/General), or ask them on [Stack Overflow](https://stackoverflow.com) using the `ImageSharp` tag. Please do not open issues for questions. - Please read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening issues or pull requests! ### Code of Conduct This project has adopted the code of conduct defined by the [Contributor Covenant](https://contributor-covenant.org/) to clarify expected behavior in our community. For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). -### API - -Our API is designed to be simple to consume. Here's an example of the code required to resize an image using the default Bicubic resampler then turn the colors into their grayscale equivalent using the BT709 standard matrix. - -On platforms supporting netstandard 1.3+ - -```csharp -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.PixelFormats; +### Installation -// Image.Load(string path) is a shortcut for our default type. -// Other pixel formats use Image.Load(string path)) -using (Image image = Image.Load("foo.jpg")) -{ - image.Mutate(x => x - .Resize(image.Width / 2, image.Height / 2) - .Grayscale()); - image.Save("bar.jpg"); // Automatic encoder selected based on extension. -} -``` - -Setting individual pixel values can be performed as follows: - -```csharp -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; - -// Individual pixels -using (var image = new Image(400, 400)) -{ - image[200, 200] = Rgba32.White; -} -``` - -`Rgba32` is our default PixelFormat, equivalent to `System.Drawing Color`. For advanced pixel format usage there are multiple [PixelFormat implementations](https://github.com/SixLabors/ImageSharp/tree/master/src/ImageSharp/PixelFormats) available allowing developers to implement their own color models in the same manner as Microsoft XNA Game Studio and MonoGame. +Install stable releases via Nuget; development releases are available via MyGet. -For more examples check out: -- [Our Documentation](https://sixlabors.github.io/docs/) -- Our [Samples Repository](https://github.com/SixLabors/Samples/tree/master/ImageSharp) -- The [beta1 blog post](https://sixlabors.com/blog/announcing-imagesharp-beta-1/) +| Package Name | Release (NuGet) | Nightly (MyGet) | +|--------------------------------|-----------------|-----------------| +| `SixLabors.ImageSharp` | [![NuGet](https://img.shields.io/nuget/v/SixLabors.ImageSharp.svg)](https://www.nuget.org/packages/SixLabors.ImageSharp/) | [![MyGet](https://img.shields.io/myget/sixlabors/v/SixLabors.ImageSharp.svg)](https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp) | ### Manual build @@ -123,8 +81,6 @@ If working with Windows please ensure that you have enabled log file paths in gi git config --system core.longpaths true ``` -### Submodules - This repository contains [git submodules](https://blog.github.com/2016-02-01-working-with-submodules/). To add the submodules to the project, navigate to the repository root and type: ``` bash @@ -137,81 +93,11 @@ Please... Spread the word, contribute algorithms, submit performance improvement ### The ImageSharp Team -Grand High Eternal Dictator +Project Owner - [James Jackson-South](https://github.com/jimbobsquarepants) Core Team - [Dirk Lemstra](https://github.com/dlemstra) - [Anton Firsov](https://github.com/antonfirsov) - [Scott Williams](https://github.com/tocsoft) -- [Brian Popow](https://github.com/brianpopow) - -### Backers - -Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/imagesharp#backer)] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### Sponsors - -Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/imagesharp#sponsor)] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +- [Brian Popow](https://github.com/brianpopow) \ No newline at end of file From faf1a67fcc64a42d3af35cba08dc9cda42055d2a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 19 Apr 2020 14:03:49 +0100 Subject: [PATCH 136/213] Bump font --- README.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 820ceb11bf..fcd5fed2d1 100644 --- a/README.md +++ b/README.md @@ -27,28 +27,28 @@ ImageSharp is designed from the ground up to be flexible and extensible. The lib Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. -### License +## License - ImageSharp is licensed under the [GNU Affero General Public License v3](https://www.gnu.org/licenses/agpl-3.0) - In addition to this license, ImageSharp is offered under a commercial license. Please visit https://sixlabors.com/pricing for details. - Open Source projects who whave taken a dependency on ImageSharp prior to adoption of the AGPLv3 license are permitted to use ImageSharp (including all future versions) under the previous [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). -### Documentation +## Documentation - [Detailed documentation](https://sixlabors.github.io/docs/) for the ImageSharp API is available. This includes additional conceptual documentation to help you get started. - Our [Samples Repository](https://github.com/SixLabors/Samples/tree/master/ImageSharp) is also available containing buildable code samples demonstrating commmon activities. -### Questions? +## Questions? - Do you have questions? We are happy to help! Please [join our Gitter channel](https://gitter.im/ImageSharp/General), or ask them on [Stack Overflow](https://stackoverflow.com) using the `ImageSharp` tag. Please do not open issues for questions. - Please read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening issues or pull requests! -### Code of Conduct +## Code of Conduct This project has adopted the code of conduct defined by the [Contributor Covenant](https://contributor-covenant.org/) to clarify expected behavior in our community. For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). -### Installation +## Installation Install stable releases via Nuget; development releases are available via MyGet. @@ -56,7 +56,7 @@ Install stable releases via Nuget; development releases are available via MyGet. |--------------------------------|-----------------|-----------------| | `SixLabors.ImageSharp` | [![NuGet](https://img.shields.io/nuget/v/SixLabors.ImageSharp.svg)](https://www.nuget.org/packages/SixLabors.ImageSharp/) | [![MyGet](https://img.shields.io/myget/sixlabors/v/SixLabors.ImageSharp.svg)](https://www.myget.org/feed/sixlabors/package/nuget/SixLabors.ImageSharp) | -### Manual build +## Manual build If you prefer, you can compile ImageSharp yourself (please do and help!) @@ -87,16 +87,13 @@ This repository contains [git submodules](https://blog.github.com/2016-02-01-wor git submodule update --init --recursive ``` -### How can you help? +## How can you help? Please... Spread the word, contribute algorithms, submit performance improvements, unit tests, no input is too little. Make sure to read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening a PR. -### The ImageSharp Team +## The ImageSharp Team -Project Owner - [James Jackson-South](https://github.com/jimbobsquarepants) - -Core Team - [Dirk Lemstra](https://github.com/dlemstra) - [Anton Firsov](https://github.com/antonfirsov) - [Scott Williams](https://github.com/tocsoft) From 63453cfa36bdd7e76f9d82ed444f45fd28e874c1 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 19 Apr 2020 17:58:49 +0100 Subject: [PATCH 137/213] Tweek extension names --- .../GraphicOptionsDefaultsExtensions.cs | 22 ++++++---- .../Extensions/Drawing/DrawImageExtensions.cs | 8 ++-- .../Extensions/Filters/LomographExtensions.cs | 4 +- .../Extensions/Filters/PolaroidExtensions.cs | 4 +- .../Overlays/BackgroundColorExtensions.cs | 4 +- .../Extensions/Overlays/GlowExtensions.cs | 10 ++--- .../Extensions/Overlays/VignetteExtensions.cs | 10 ++--- .../GraphicOptionsDefaultsExtensionsTests.cs | 42 +++++++++---------- .../BaseImageOperationsExtensionTest.cs | 3 +- .../Processing/Filters/ContrastTest.cs | 4 +- 10 files changed, 58 insertions(+), 53 deletions(-) diff --git a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs index 45e444ffe3..10909c4f31 100644 --- a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs +++ b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs @@ -16,11 +16,13 @@ namespace SixLabors.ImageSharp /// /// The image processing context to store default against. /// The action to update instance of the default options used. - public static void SetDefaultOptions(this IImageProcessingContext context, Action optionsBuilder) + /// The passed in to allow chaining. + public static IImageProcessingContext SetGraphicsOptions(this IImageProcessingContext context, Action optionsBuilder) { - var cloned = context.GetDefaultGraphicsOptions().DeepClone(); + var cloned = context.GetGraphicsOptions().DeepClone(); optionsBuilder(cloned); context.Properties[typeof(GraphicsOptions)] = cloned; + return context; } /// @@ -28,9 +30,9 @@ namespace SixLabors.ImageSharp /// /// The image processing context to store default against. /// The default options to use. - public static void SetDefaultGraphicsOptions(this Configuration context, Action optionsBuilder) + public static void SetGraphicsOptions(this Configuration context, Action optionsBuilder) { - var cloned = context.GetDefaultGraphicsOptions().DeepClone(); + var cloned = context.GetGraphicsOptions().DeepClone(); optionsBuilder(cloned); context.Properties[typeof(GraphicsOptions)] = cloned; } @@ -40,9 +42,11 @@ namespace SixLabors.ImageSharp /// /// The image processing context to store default against. /// The default options to use. - public static void SetDefaultOptions(this IImageProcessingContext context, GraphicsOptions options) + /// The passed in to allow chaining. + public static IImageProcessingContext SetGraphicsOptions(this IImageProcessingContext context, GraphicsOptions options) { context.Properties[typeof(GraphicsOptions)] = options; + return context; } /// @@ -50,7 +54,7 @@ namespace SixLabors.ImageSharp /// /// The image processing context to store default against. /// The default options to use. - public static void SetDefaultGraphicsOptions(this Configuration context, GraphicsOptions options) + public static void SetGraphicsOptions(this Configuration context, GraphicsOptions options) { context.Properties[typeof(GraphicsOptions)] = options; } @@ -60,14 +64,14 @@ namespace SixLabors.ImageSharp /// /// The image processing context to retrieve defaults from. /// The globaly configued default options. - public static GraphicsOptions GetDefaultGraphicsOptions(this IImageProcessingContext context) + public static GraphicsOptions GetGraphicsOptions(this IImageProcessingContext context) { if (context.Properties.TryGetValue(typeof(GraphicsOptions), out var options) && options is GraphicsOptions go) { return go; } - var configOptions = context.Configuration.GetDefaultGraphicsOptions(); + var configOptions = context.Configuration.GetGraphicsOptions(); // do not cache the fall back to config into the the processing context // in case someone want to change the value on the config and expects it re trflow thru @@ -79,7 +83,7 @@ namespace SixLabors.ImageSharp /// /// The image processing context to retrieve defaults from. /// The globaly configued default options. - public static GraphicsOptions GetDefaultGraphicsOptions(this Configuration context) + public static GraphicsOptions GetGraphicsOptions(this Configuration context) { if (context.Properties.TryGetValue(typeof(GraphicsOptions), out var options) && options is GraphicsOptions go) { diff --git a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs index 197dcd3efa..3c25bb7c40 100644 --- a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing Image image, float opacity) { - var options = source.GetDefaultGraphicsOptions(); + var options = source.GetGraphicsOptions(); return source.ApplyProcessor( new DrawImageProcessor( image, @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing image, Point.Empty, colorBlending, - source.GetDefaultGraphicsOptions().AlphaCompositionMode, + source.GetGraphicsOptions().AlphaCompositionMode, opacity)); /// @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Processing Point location, float opacity) { - var options = source.GetDefaultGraphicsOptions(); + var options = source.GetGraphicsOptions(); return source.ApplyProcessor( new DrawImageProcessor( image, @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.Processing image, location, colorBlending, - source.GetDefaultGraphicsOptions().AlphaCompositionMode, + source.GetGraphicsOptions().AlphaCompositionMode, opacity)); /// diff --git a/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs index b46f53cf6a..3f8a67feb3 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Lomograph(this IImageProcessingContext source) - => source.ApplyProcessor(new LomographProcessor(source.GetDefaultGraphicsOptions())); + => source.ApplyProcessor(new LomographProcessor(source.GetGraphicsOptions())); /// /// Alters the colors of the image recreating an old Lomograph camera effect. @@ -28,6 +28,6 @@ namespace SixLabors.ImageSharp.Processing /// /// The to allow chaining of operations. public static IImageProcessingContext Lomograph(this IImageProcessingContext source, Rectangle rectangle) - => source.ApplyProcessor(new LomographProcessor(source.GetDefaultGraphicsOptions()), rectangle); + => source.ApplyProcessor(new LomographProcessor(source.GetGraphicsOptions()), rectangle); } } diff --git a/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs index 4e216b4f78..ab75ea56b5 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Polaroid(this IImageProcessingContext source) - => source.ApplyProcessor(new PolaroidProcessor(source.GetDefaultGraphicsOptions())); + => source.ApplyProcessor(new PolaroidProcessor(source.GetGraphicsOptions())); /// /// Alters the colors of the image recreating an old Polaroid camera effect. @@ -28,6 +28,6 @@ namespace SixLabors.ImageSharp.Processing /// /// The to allow chaining of operations. public static IImageProcessingContext Polaroid(this IImageProcessingContext source, Rectangle rectangle) - => source.ApplyProcessor(new PolaroidProcessor(source.GetDefaultGraphicsOptions()), rectangle); + => source.ApplyProcessor(new PolaroidProcessor(source.GetGraphicsOptions()), rectangle); } } diff --git a/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs index ced37091ee..21e244f0a3 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing /// The color to set as the background. /// The to allow chaining of operations. public static IImageProcessingContext BackgroundColor(this IImageProcessingContext source, Color color) => - BackgroundColor(source, source.GetDefaultGraphicsOptions(), color); + BackgroundColor(source, source.GetGraphicsOptions(), color); /// /// Replaces the background color of image with the given one. @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing this IImageProcessingContext source, Color color, Rectangle rectangle) => - BackgroundColor(source, source.GetDefaultGraphicsOptions(), color, rectangle); + BackgroundColor(source, source.GetGraphicsOptions(), color, rectangle); /// /// Replaces the background color of image with the given one. diff --git a/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs index 63f0651193..c3ce32e636 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source) => - Glow(source, source.GetDefaultGraphicsOptions()); + Glow(source, source.GetGraphicsOptions()); /// /// Applies a radial glow effect to an image. @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, Color color) { - return Glow(source, source.GetDefaultGraphicsOptions(), color); + return Glow(source, source.GetGraphicsOptions(), color); } /// @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing /// The the radius. /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, float radius) => - Glow(source, source.GetDefaultGraphicsOptions(), radius); + Glow(source, source.GetGraphicsOptions(), radius); /// /// Applies a radial glow effect to an image. @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The to allow chaining of operations. public static IImageProcessingContext Glow(this IImageProcessingContext source, Rectangle rectangle) => - source.Glow(source.GetDefaultGraphicsOptions(), rectangle); + source.Glow(source.GetGraphicsOptions(), rectangle); /// /// Applies a radial glow effect to an image. @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing Color color, float radius, Rectangle rectangle) => - source.Glow(source.GetDefaultGraphicsOptions(), color, ValueSize.Absolute(radius), rectangle); + source.Glow(source.GetGraphicsOptions(), color, ValueSize.Absolute(radius), rectangle); /// /// Applies a radial glow effect to an image. diff --git a/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs index a3063832af..b53880fc12 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing /// The image this method extends. /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source) => - Vignette(source, source.GetDefaultGraphicsOptions()); + Vignette(source, source.GetGraphicsOptions()); /// /// Applies a radial vignette effect to an image. @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Processing /// The color to set as the vignette. /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source, Color color) => - Vignette(source, source.GetDefaultGraphicsOptions(), color); + Vignette(source, source.GetGraphicsOptions(), color); /// /// Applies a radial vignette effect to an image. @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing this IImageProcessingContext source, float radiusX, float radiusY) => - Vignette(source, source.GetDefaultGraphicsOptions(), radiusX, radiusY); + Vignette(source, source.GetGraphicsOptions(), radiusX, radiusY); /// /// Applies a radial vignette effect to an image. @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The to allow chaining of operations. public static IImageProcessingContext Vignette(this IImageProcessingContext source, Rectangle rectangle) => - Vignette(source, source.GetDefaultGraphicsOptions(), rectangle); + Vignette(source, source.GetGraphicsOptions(), rectangle); /// /// Applies a radial vignette effect to an image. @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing float radiusX, float radiusY, Rectangle rectangle) => - source.Vignette(source.GetDefaultGraphicsOptions(), color, radiusX, radiusY, rectangle); + source.Vignette(source.GetGraphicsOptions(), color, radiusX, radiusY, rectangle); /// /// Applies a radial vignette effect to an image. diff --git a/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs b/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs index 4b0d7a62d5..9c02dd601e 100644 --- a/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs +++ b/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests var config = new Configuration(); var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); - context.SetDefaultOptions(option); + context.SetGraphicsOptions(option); // sets the prop on the processing context not on the configuration Assert.Equal(option, context.Properties[typeof(GraphicsOptions)]); @@ -33,15 +33,15 @@ namespace SixLabors.ImageSharp.Tests }; var config = new Configuration(); var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); - context.SetDefaultOptions(option); + context.SetGraphicsOptions(option); - context.SetDefaultOptions(o => + context.SetGraphicsOptions(o => { Assert.Equal(0.9f, o.BlendPercentage); // has origional values o.BlendPercentage = 0.4f; }); - var returnedOption = context.GetDefaultGraphicsOptions(); + var returnedOption = context.GetGraphicsOptions(); Assert.Equal(0.4f, returnedOption.BlendPercentage); Assert.Equal(0.9f, option.BlendPercentage); // hasn't been mutated } @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests var option = new GraphicsOptions(); var config = new Configuration(); - config.SetDefaultGraphicsOptions(option); + config.SetGraphicsOptions(option); Assert.Equal(option, config.Properties[typeof(GraphicsOptions)]); } @@ -65,15 +65,15 @@ namespace SixLabors.ImageSharp.Tests BlendPercentage = 0.9f }; var config = new Configuration(); - config.SetDefaultGraphicsOptions(option); + config.SetGraphicsOptions(option); - config.SetDefaultGraphicsOptions(o => + config.SetGraphicsOptions(o => { Assert.Equal(0.9f, o.BlendPercentage); // has origional values o.BlendPercentage = 0.4f; }); - var returnedOption = config.GetDefaultGraphicsOptions(); + var returnedOption = config.GetGraphicsOptions(); Assert.Equal(0.4f, returnedOption.BlendPercentage); Assert.Equal(0.9f, option.BlendPercentage); // hasn't been mutated } @@ -83,11 +83,11 @@ namespace SixLabors.ImageSharp.Tests { var config = new Configuration(); - var options = config.GetDefaultGraphicsOptions(); + var options = config.GetGraphicsOptions(); Assert.NotNull(options); - config.SetDefaultGraphicsOptions((GraphicsOptions)null); + config.SetGraphicsOptions((GraphicsOptions)null); - var options2 = config.GetDefaultGraphicsOptions(); + var options2 = config.GetGraphicsOptions(); Assert.NotNull(options2); // we set it to null should now be a new instance @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.Tests var config = new Configuration(); config.Properties[typeof(GraphicsOptions)] = "wronge type"; - var options = config.GetDefaultGraphicsOptions(); + var options = config.GetGraphicsOptions(); Assert.NotNull(options); Assert.IsType(options); } @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Tests var config = new Configuration(); Assert.DoesNotContain(typeof(GraphicsOptions), config.Properties.Keys); - var options = config.GetDefaultGraphicsOptions(); + var options = config.GetGraphicsOptions(); Assert.NotNull(options); } @@ -120,8 +120,8 @@ namespace SixLabors.ImageSharp.Tests { var config = new Configuration(); - var options = config.GetDefaultGraphicsOptions(); - var options2 = config.GetDefaultGraphicsOptions(); + var options = config.GetGraphicsOptions(); + var options2 = config.GetGraphicsOptions(); Assert.Equal(options, options2); } @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Tests var config = new Configuration(); var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); - var ctxOptions = context.GetDefaultGraphicsOptions(); + var ctxOptions = context.GetGraphicsOptions(); Assert.NotNull(ctxOptions); } @@ -141,8 +141,8 @@ namespace SixLabors.ImageSharp.Tests var config = new Configuration(); var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); - context.SetDefaultOptions((GraphicsOptions)null); - var ctxOptions = context.GetDefaultGraphicsOptions(); + context.SetGraphicsOptions((GraphicsOptions)null); + var ctxOptions = context.GetGraphicsOptions(); Assert.NotNull(ctxOptions); } @@ -151,10 +151,10 @@ namespace SixLabors.ImageSharp.Tests { var option = new GraphicsOptions(); var config = new Configuration(); - config.SetDefaultGraphicsOptions(option); + config.SetGraphicsOptions(option); var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); - var ctxOptions = context.GetDefaultGraphicsOptions(); + var ctxOptions = context.GetGraphicsOptions(); Assert.Equal(option, ctxOptions); } @@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Tests var config = new Configuration(); var context = new FakeImageOperationsProvider.FakeImageOperations(config, null, true); context.Properties[typeof(GraphicsOptions)] = "wronge type"; - var options = context.GetDefaultGraphicsOptions(); + var options = context.GetGraphicsOptions(); Assert.NotNull(options); Assert.IsType(options); } diff --git a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs index da20401310..953563006b 100644 --- a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs +++ b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.ComponentModel.DataAnnotations; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; @@ -25,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Processing this.source = new Image(91 + 324, 123 + 56); this.rect = new Rectangle(91, 123, 324, 56); // make this random? this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(this.source.GetConfiguration(), this.source, false); - this.internalOperations.SetDefaultOptions(this.options); + this.internalOperations.SetGraphicsOptions(this.options); this.operations = this.internalOperations; } diff --git a/tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs b/tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs index e55e983dad..bf2d6823ad 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using Xunit; @@ -28,4 +28,4 @@ namespace SixLabors.ImageSharp.Tests.Processing.Effects Assert.Equal(1.5F, processor.Amount); } } -} \ No newline at end of file +} From ff2d59ea08cf18441698271e083e16d0122e63e5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 20 Apr 2020 00:02:54 +0100 Subject: [PATCH 138/213] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fcd5fed2d1..5e48aaa47c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

-SixLabors.ImageSharp +SixLabors.ImageSharp
SixLabors.ImageSharp

@@ -30,16 +30,16 @@ Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standa ## License - ImageSharp is licensed under the [GNU Affero General Public License v3](https://www.gnu.org/licenses/agpl-3.0) -- In addition to this license, ImageSharp is offered under a commercial license. +- An alternative Commercial License can be purchased for Closed Source projects and applications. Please visit https://sixlabors.com/pricing for details. -- Open Source projects who whave taken a dependency on ImageSharp prior to adoption of the AGPLv3 license are permitted to use ImageSharp (including all future versions) under the previous [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). +- Open Source projects who whave taken a dependency on ImageSharp prior to adoption of the AGPL v3 license are permitted to use ImageSharp (including all future versions) under the previous [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). ## Documentation - [Detailed documentation](https://sixlabors.github.io/docs/) for the ImageSharp API is available. This includes additional conceptual documentation to help you get started. - Our [Samples Repository](https://github.com/SixLabors/Samples/tree/master/ImageSharp) is also available containing buildable code samples demonstrating commmon activities. -## Questions? +## Questions - Do you have questions? We are happy to help! Please [join our Gitter channel](https://gitter.im/ImageSharp/General), or ask them on [Stack Overflow](https://stackoverflow.com) using the `ImageSharp` tag. Please do not open issues for questions. - Please read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening issues or pull requests! From 7fb1612c302da9c8a63358db666b6965faa33744 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 20 Apr 2020 00:30:18 +0100 Subject: [PATCH 139/213] Remove allocation and clean up docs --- .../Metadata/Profiles/IPTC/IptcProfile.cs | 5 +---- .../Metadata/Profiles/IPTC/IptcTag.cs | 2 +- .../Metadata/Profiles/IPTC/IptcValue.cs | 18 ++++++++---------- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index b46eee0fd9..9206e43771 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -10,11 +10,8 @@ using System.Text; namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { /// - /// Class that can be used to access an Iptc profile. + /// Represents an IPTC profile providing access to the collection of values. /// - /// This source code is from the Magick.Net project: - /// https://github.com/dlemstra/Magick.NET/tree/master/src/Magick.NET/Shared/Profiles/Iptc/IptcProfile.cs - /// public sealed class IptcProfile : IDeepCloneable { private Collection values; diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs index 70a90aa108..7258a02917 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs @@ -4,7 +4,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { /// - /// All iptc tags relevant for images. + /// Provides enumeration of all IPTC tags relevant for images. /// public enum IptcTag { diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs index 8e804353c6..e63781012a 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs @@ -7,11 +7,11 @@ using System.Text; namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { /// - /// A value of the iptc profile. + /// Represents a single value of the IPTC profile. /// public sealed class IptcValue : IDeepCloneable { - private byte[] data; + private byte[] data = Array.Empty(); private Encoding encoding; internal IptcValue(IptcValue other) @@ -165,16 +165,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc return false; } - byte[] data = other.ToByteArray(); - - if (this.data.Length != data.Length) + if (this.data.Length != other.data.Length) { return false; } for (int i = 0; i < this.data.Length; i++) { - if (this.data[i] != data[i]) + if (this.data[i] != other.data[i]) { return false; } @@ -209,13 +207,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc /// /// Returns a string that represents the current value with the specified encoding. /// - /// The encoding to use. + /// The encoding to use. /// A string that represents the current value with the specified encoding. - public string ToString(Encoding enc) + public string ToString(Encoding encoding) { - Guard.NotNull(enc, nameof(enc)); + Guard.NotNull(encoding, nameof(encoding)); - return enc.GetString(this.data); + return encoding.GetString(this.data); } } } From ccbb6d95f69bb6baad7aa37b046e58dc199b6e64 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 21 Apr 2020 14:57:03 +0100 Subject: [PATCH 140/213] Always read CRC. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 7 +----- .../Formats/Png/PngDecoderTests.cs | 23 ++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 4 +++ .../Images/Input/Png/issues/Issue_1177_1.png | Bin 0 -> 7023 bytes .../Images/Input/Png/issues/Issue_1177_2.png | Bin 0 -> 57125 bytes 5 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Png/issues/Issue_1177_1.png create mode 100644 tests/Images/Input/Png/issues/Issue_1177_2.png diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index bc7b9d8150..e2cd806314 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1141,11 +1141,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// The . private void ValidateChunk(in PngChunk chunk) { - if (!chunk.IsCritical) - { - return; - } - Span chunkType = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); @@ -1155,7 +1150,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.crc.Update(chunk.Data.GetSpan()); uint crc = this.ReadChunkCrc(); - if (this.crc.Value != crc) + if (this.crc.Value != crc && chunk.IsCritical) { string chunkTypeName = Encoding.ASCII.GetString(chunkType); PngThrowHelper.ThrowInvalidChunkCrc(chunkTypeName); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 46112bdd81..b08025f532 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -89,6 +89,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png TestImages.Png.Issue1014_5, TestImages.Png.Issue1014_6 }; + public static readonly string[] TestImagesIssue1177 = + { + TestImages.Png.Issue1177_1, + TestImages.Png.Issue1177_2 + }; + [Theory] [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] public void Decode(TestImageProvider provider) @@ -243,6 +249,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Null(ex); } + [Theory] + [WithFileCollection(nameof(TestImagesIssue1177), PixelTypes.Rgba32)] + public void Issue1177(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + System.Exception ex = Record.Exception( + () => + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); + } + }); + Assert.Null(ex); + } + [Theory] [WithFile(TestImages.Png.Issue1127, PixelTypes.Rgba32)] public void Issue1127(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 65d9752573..18fd84331f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -95,6 +95,10 @@ namespace SixLabors.ImageSharp.Tests public const string Issue1014_6 = "Png/issues/Issue_1014_6.png"; public const string Issue1127 = "Png/issues/Issue_1127.png"; + // Issue 1177: https://github.com/SixLabors/ImageSharp/issues/1177 + public const string Issue1177_1 = "Png/issues/Issue_1177_1.png"; + public const string Issue1177_2 = "Png/issues/Issue_1177_2.png"; + public static class Bad { // Odd chunk lengths diff --git a/tests/Images/Input/Png/issues/Issue_1177_1.png b/tests/Images/Input/Png/issues/Issue_1177_1.png new file mode 100644 index 0000000000000000000000000000000000000000..5db6ae24cf63cbc752c21f02f5e1645b1779ef94 GIT binary patch literal 7023 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 YNfIw8;oglZzkaS&l2eoYC}SG%Kj?z2H~;_u literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/issues/Issue_1177_2.png b/tests/Images/Input/Png/issues/Issue_1177_2.png new file mode 100644 index 0000000000000000000000000000000000000000..ba8fcbdb039fdcd22bf74b026077629035d3a68c GIT binary patch literal 57125 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 Date: Tue, 21 Apr 2020 18:15:00 +0100 Subject: [PATCH 141/213] No need to calculate CRC for non-critical chunks. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 23 +++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index e2cd806314..272f93d108 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1141,19 +1141,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// The . private void ValidateChunk(in PngChunk chunk) { - Span chunkType = stackalloc byte[4]; + uint crc = this.ReadChunkCrc(); - BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); + if (chunk.IsCritical) + { + Span chunkType = stackalloc byte[4]; + BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); - this.crc.Reset(); - this.crc.Update(chunkType); - this.crc.Update(chunk.Data.GetSpan()); + this.crc.Reset(); + this.crc.Update(chunkType); + this.crc.Update(chunk.Data.GetSpan()); - uint crc = this.ReadChunkCrc(); - if (this.crc.Value != crc && chunk.IsCritical) - { - string chunkTypeName = Encoding.ASCII.GetString(chunkType); - PngThrowHelper.ThrowInvalidChunkCrc(chunkTypeName); + if (this.crc.Value != crc) + { + string chunkTypeName = Encoding.ASCII.GetString(chunkType); + PngThrowHelper.ThrowInvalidChunkCrc(chunkTypeName); + } } } From ad6da51a3d773823c473879aa76687001069b538 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 21 Apr 2020 19:50:31 +0100 Subject: [PATCH 142/213] Introduce InvalidImageContentException, document and guard all load methods --- .../InvalidImageContentException.cs | 22 +++ src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 10 +- src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs | 16 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifThrowHelper.cs | 18 +++ .../JpegColorConverter.FromYCbCrSimd.cs | 4 +- .../Jpeg/Components/Decoder/JFifMarker.cs | 4 +- .../Formats/Jpeg/JpegDecoderCore.cs | 18 +-- .../Formats/Jpeg/JpegThrowHelper.cs | 27 ++-- src/ImageSharp/Formats/Png/PngThrowHelper.cs | 10 +- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 6 +- src/ImageSharp/Formats/Tga/TgaThrowHelper.cs | 14 +- src/ImageSharp/Image.FromBytes.cs | 147 +++++++++++++++--- src/ImageSharp/Image.FromFile.cs | 119 ++++++++------ src/ImageSharp/Image.FromStream.cs | 131 +++++++++++----- src/ImageSharp/Image.LoadPixelData.cs | 43 +++-- src/ImageSharp/Image.WrapMemory.cs | 50 +++--- 18 files changed, 432 insertions(+), 211 deletions(-) create mode 100644 src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs create mode 100644 src/ImageSharp/Formats/Gif/GifThrowHelper.cs diff --git a/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs b/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs new file mode 100644 index 0000000000..7069e89823 --- /dev/null +++ b/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp +{ + /// + /// The exception that is thrown when the library tries to load + /// an image which contains invalid content. + /// + public sealed class InvalidImageContentException : ImageFormatException + { + /// + /// Initializes a new instance of the class with the name of the + /// parameter that causes this exception. + /// + /// The error message that explains the reason for this exception. + public InvalidImageContentException(string errorMessage) + : base(errorMessage) + { + } + } +} diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index dfdbb22fa5..eeb1ae714a 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -462,7 +462,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { if (this.stream.Read(cmd, 0, cmd.Length) != 2) { - BmpThrowHelper.ThrowImageFormatException("Failed to read 2 bytes from the stream while uncompressing RLE4 bitmap."); + BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from the stream while uncompressing RLE4 bitmap."); } if (cmd[0] == RleCommand) @@ -569,7 +569,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { if (this.stream.Read(cmd, 0, cmd.Length) != 2) { - BmpThrowHelper.ThrowImageFormatException("Failed to read 2 bytes from stream while uncompressing RLE8 bitmap."); + BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from stream while uncompressing RLE8 bitmap."); } if (cmd[0] == RleCommand) @@ -648,7 +648,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { if (this.stream.Read(cmd, 0, cmd.Length) != 2) { - BmpThrowHelper.ThrowImageFormatException("Failed to read 2 bytes from stream while uncompressing RLE24 bitmap."); + BmpThrowHelper.ThrowInvalidImageContentException("Failed to read 2 bytes from stream while uncompressing RLE24 bitmap."); } if (cmd[0] == RleCommand) @@ -1431,7 +1431,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp // Make sure, that we will not read pass the bitmap offset (starting position of image data). if ((this.stream.Position + colorMapSizeBytes) > this.fileHeader.Offset) { - BmpThrowHelper.ThrowImageFormatException( + BmpThrowHelper.ThrowInvalidImageContentException( $"Reading the color map would read beyond the bitmap offset. Either the color map size of '{colorMapSizeBytes}' is invalid or the bitmap offset."); } @@ -1445,7 +1445,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp int skipAmount = this.fileHeader.Offset - (int)this.stream.Position; if ((skipAmount + (int)this.stream.Position) > this.stream.Length) { - BmpThrowHelper.ThrowImageFormatException("Invalid fileheader offset found. Offset is greater than the stream length."); + BmpThrowHelper.ThrowInvalidImageContentException("Invalid fileheader offset found. Offset is greater than the stream length."); } if (skipAmount > 0) diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index 9ede660705..3411de0421 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -393,7 +393,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp break; default: // Compression type 3 (1DHuffman) is not supported. - BmpThrowHelper.ThrowImageFormatException("Compression type is not supported. ImageSharp only supports uncompressed, RLE4, RLE8 and RLE24."); + BmpThrowHelper.ThrowInvalidImageContentException("Compression type is not supported. ImageSharp only supports uncompressed, RLE4, RLE8 and RLE24."); break; } diff --git a/src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs b/src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs index 443471404e..c48566f835 100644 --- a/src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs +++ b/src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -9,23 +9,19 @@ namespace SixLabors.ImageSharp.Formats.Bmp internal static class BmpThrowHelper { /// - /// Cold path optimization for throwing -s + /// Cold path optimization for throwing 's /// /// The error message for the exception. [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowImageFormatException(string errorMessage) - { - throw new ImageFormatException(errorMessage); - } + public static void ThrowInvalidImageContentException(string errorMessage) + => throw new InvalidImageContentException(errorMessage); /// - /// Cold path optimization for throwing -s + /// Cold path optimization for throwing 's /// /// The error message for the exception. [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowNotSupportedException(string errorMessage) - { - throw new NotSupportedException(errorMessage); - } + => throw new NotSupportedException(errorMessage); } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 7919bc1489..de5aa78843 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -318,7 +318,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { if (length > GifConstants.MaxCommentSubBlockLength) { - throw new ImageFormatException($"Gif comment length '{length}' exceeds max '{GifConstants.MaxCommentSubBlockLength}' of a comment data block"); + GifThrowHelper.ThrowInvalidImageContentException($"Gif comment length '{length}' exceeds max '{GifConstants.MaxCommentSubBlockLength}' of a comment data block"); } if (this.IgnoreMetadata) diff --git a/src/ImageSharp/Formats/Gif/GifThrowHelper.cs b/src/ImageSharp/Formats/Gif/GifThrowHelper.cs new file mode 100644 index 0000000000..1d81008a01 --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifThrowHelper.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.Formats.Gif +{ + internal static class GifThrowHelper + { + /// + /// Cold path optimization for throwing 's + /// + /// The error message for the exception. + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowInvalidImageContentException(string errorMessage) + => throw new InvalidImageContentException(errorMessage); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 09d6a4d1d8..002f79f84c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { // TODO: Run fallback scalar code here // However, no issues expected before someone implements this: https://github.com/dotnet/coreclr/issues/12007 - throw new NotImplementedException("Your CPU architecture is too modern!"); + JpegThrowHelper.ThrowNotImplementedException("Your CPU architecture is too modern!"); } // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs index 7497c8a409..44878bd6c7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs @@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { if (xDensity <= 0) { - JpegThrowHelper.ThrowImageFormatException($"X-Density {xDensity} must be greater than 0."); + JpegThrowHelper.ThrowInvalidImageContentException($"X-Density {xDensity} must be greater than 0."); } if (yDensity <= 0) { - JpegThrowHelper.ThrowImageFormatException($"Y-Density {yDensity} must be greater than 0."); + JpegThrowHelper.ThrowInvalidImageContentException($"Y-Density {yDensity} must be greater than 0."); } this.MajorVersion = majorVersion; diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 4000fa0f62..654610659d 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg var fileMarker = new JpegFileMarker(this.markerBuffer[1], 0); if (fileMarker.Marker != JpegConstants.Markers.SOI) { - JpegThrowHelper.ThrowImageFormatException("Missing SOI marker."); + JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker."); } this.InputStream.Read(this.markerBuffer, 0, 2); @@ -423,7 +423,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg : JpegColorSpace.Cmyk; } - JpegThrowHelper.ThrowImageFormatException($"Unsupported color mode. Supported component counts 1, 3, and 4; found {this.ComponentCount}"); + JpegThrowHelper.ThrowInvalidImageContentException($"Unsupported color mode. Supported component counts 1, 3, and 4; found {this.ComponentCount}"); return default; } @@ -821,7 +821,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { if (this.Frame != null) { - JpegThrowHelper.ThrowImageFormatException("Multiple SOF markers. Only single frame jpegs supported."); + JpegThrowHelper.ThrowInvalidImageContentException("Multiple SOF markers. Only single frame jpegs supported."); } // Read initial marker definitions. @@ -831,7 +831,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // We only support 8-bit and 12-bit precision. if (Array.IndexOf(this.supportedPrecisions, this.temp[0]) == -1) { - JpegThrowHelper.ThrowImageFormatException("Only 8-Bit and 12-Bit precision supported."); + JpegThrowHelper.ThrowInvalidImageContentException("Only 8-Bit and 12-Bit precision supported."); } this.Precision = this.temp[0]; @@ -928,13 +928,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // Types 0..1 DC..AC if (tableType > 1) { - JpegThrowHelper.ThrowImageFormatException("Bad Huffman Table type."); + JpegThrowHelper.ThrowInvalidImageContentException("Bad Huffman Table type."); } // Max tables of each type if (tableIndex > 3) { - JpegThrowHelper.ThrowImageFormatException("Bad Huffman Table index."); + JpegThrowHelper.ThrowInvalidImageContentException("Bad Huffman Table index."); } this.InputStream.Read(huffmanData.Array, 0, 16); @@ -953,7 +953,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg if (codeLengthSum > 256 || codeLengthSum > length) { - JpegThrowHelper.ThrowImageFormatException("Huffman table has excessive length."); + JpegThrowHelper.ThrowInvalidImageContentException("Huffman table has excessive length."); } using (IManagedByteBuffer huffmanValues = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(256, AllocationOptions.Clean)) @@ -995,7 +995,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { if (this.Frame is null) { - JpegThrowHelper.ThrowImageFormatException("No readable SOFn (Start Of Frame) marker found."); + JpegThrowHelper.ThrowInvalidImageContentException("No readable SOFn (Start Of Frame) marker found."); } int selectorsCount = this.InputStream.ReadByte(); @@ -1016,7 +1016,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg if (componentIndex < 0) { - JpegThrowHelper.ThrowImageFormatException($"Unknown component selector {componentIndex}."); + JpegThrowHelper.ThrowInvalidImageContentException($"Unknown component selector {componentIndex}."); } ref JpegComponent component = ref this.Frame.Components[componentIndex]; diff --git a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs index 7e8384dcff..dd44cb2d19 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs @@ -1,6 +1,7 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Jpeg @@ -8,25 +9,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg internal static class JpegThrowHelper { /// - /// Cold path optimization for throwing 's. + /// Cold path optimization for throwing 's. /// /// The error message for the exception. [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowImageFormatException(string errorMessage) => throw new ImageFormatException(errorMessage); + public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage); + + /// + /// Cold path optimization for throwing 's + /// + /// The error message for the exception. + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowNotImplementedException(string errorMessage) + => throw new NotImplementedException(errorMessage); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowBadMarker(string marker, int length) => throw new ImageFormatException($"Marker {marker} has bad length {length}."); + public static void ThrowBadMarker(string marker, int length) => throw new InvalidImageContentException($"Marker {marker} has bad length {length}."); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowBadQuantizationTable() => throw new ImageFormatException("Bad Quantization Table index."); + public static void ThrowBadQuantizationTable() => throw new InvalidImageContentException("Bad Quantization Table index."); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowBadSampling() => throw new ImageFormatException("Bad sampling factor."); + public static void ThrowBadSampling() => throw new InvalidImageContentException("Bad sampling factor."); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowBadProgressiveScan(int ss, int se, int ah, int al) => throw new ImageFormatException($"Invalid progressive parameters Ss={ss} Se={se} Ah={ah} Al={al}."); + public static void ThrowBadProgressiveScan(int ss, int se, int ah, int al) => throw new InvalidImageContentException($"Invalid progressive parameters Ss={ss} Se={se} Ah={ah} Al={al}."); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowInvalidImageDimensions(int width, int height) => throw new ImageFormatException($"Invalid image dimensions: {width}x{height}."); + public static void ThrowInvalidImageDimensions(int width, int height) => throw new InvalidImageContentException($"Invalid image dimensions: {width}x{height}."); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Png/PngThrowHelper.cs b/src/ImageSharp/Formats/Png/PngThrowHelper.cs index dd3a054641..dcb643d036 100644 --- a/src/ImageSharp/Formats/Png/PngThrowHelper.cs +++ b/src/ImageSharp/Formats/Png/PngThrowHelper.cs @@ -12,21 +12,21 @@ namespace SixLabors.ImageSharp.Formats.Png internal static class PngThrowHelper { [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowNoHeader() => throw new ImageFormatException("PNG Image does not contain a header chunk"); + public static void ThrowNoHeader() => throw new InvalidImageContentException("PNG Image does not contain a header chunk"); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowNoData() => throw new ImageFormatException("PNG Image does not contain a data chunk"); + public static void ThrowNoData() => throw new InvalidImageContentException("PNG Image does not contain a data chunk"); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowInvalidChunkType() => throw new ImageFormatException("Invalid PNG data."); + public static void ThrowInvalidChunkType() => throw new InvalidImageContentException("Invalid PNG data."); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowInvalidChunkCrc(string chunkTypeName) => throw new ImageFormatException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!"); + public static void ThrowInvalidChunkCrc(string chunkTypeName) => throw new InvalidImageContentException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!"); [MethodImpl(InliningOptions.ColdPath)] public static void ThrowNotSupportedColor() => new NotSupportedException("Unsupported PNG color type"); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowUnknownFilter() => throw new ImageFormatException("Unknown filter type."); + public static void ThrowUnknownFilter() => throw new InvalidImageContentException("Unknown filter type."); } } diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 816a472fb2..057ec1bfc7 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -114,12 +114,12 @@ namespace SixLabors.ImageSharp.Formats.Tga { if (this.fileHeader.CMapLength <= 0) { - TgaThrowHelper.ThrowImageFormatException("Missing tga color map length"); + TgaThrowHelper.ThrowInvalidImageContentException("Missing tga color map length"); } if (this.fileHeader.CMapDepth <= 0) { - TgaThrowHelper.ThrowImageFormatException("Missing tga color map depth"); + TgaThrowHelper.ThrowInvalidImageContentException("Missing tga color map depth"); } int colorMapPixelSizeInBytes = this.fileHeader.CMapDepth / 8; @@ -898,7 +898,7 @@ namespace SixLabors.ImageSharp.Formats.Tga var alphaBits = this.fileHeader.ImageDescriptor & 0xf; if (alphaBits != 0 && alphaBits != 1 && alphaBits != 8) { - TgaThrowHelper.ThrowImageFormatException("Invalid alpha channel bits"); + TgaThrowHelper.ThrowInvalidImageContentException("Invalid alpha channel bits"); } this.tgaMetadata.AlphaChannelBits = (byte)alphaBits; diff --git a/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs b/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs index 845d009227..1714a2025e 100644 --- a/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs +++ b/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs @@ -9,23 +9,19 @@ namespace SixLabors.ImageSharp.Formats.Tga internal static class TgaThrowHelper { /// - /// Cold path optimization for throwing -s + /// Cold path optimization for throwing 's /// /// The error message for the exception. [MethodImpl(MethodImplOptions.NoInlining)] - public static void ThrowImageFormatException(string errorMessage) - { - throw new ImageFormatException(errorMessage); - } + public static void ThrowInvalidImageContentException(string errorMessage) + => throw new InvalidImageContentException(errorMessage); /// - /// Cold path optimization for throwing -s + /// Cold path optimization for throwing 's /// /// The error message for the exception. [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowNotSupportedException(string errorMessage) - { - throw new NotSupportedException(errorMessage); - } + => throw new NotSupportedException(errorMessage); } } diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 06b05fe3c4..a0e8097d8e 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -17,21 +17,23 @@ namespace SixLabors.ImageSharp /// By reading the header on the provided byte array this calculates the images format. ///
/// The byte array containing encoded image data to read the header from. + /// The data is null. /// The format or null if none found. public static IImageFormat DetectFormat(byte[] data) - { - return DetectFormat(Configuration.Default, data); - } + => DetectFormat(Configuration.Default, data); /// /// By reading the header on the provided byte array this calculates the images format. /// /// The configuration. /// The byte array containing encoded image data to read the header from. + /// The configuration is null. + /// The data is null. /// The mime type or null if none found. public static IImageFormat DetectFormat(Configuration configuration, byte[] data) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(data, nameof(data)); + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return DetectFormat(configuration, stream); @@ -42,7 +44,8 @@ namespace SixLabors.ImageSharp /// Reads the raw image information from the specified stream without fully decoding it. ///
/// The byte array containing encoded image data to read the header from. - /// Thrown if the stream is not readable. + /// The data is null. + /// The data is not readable. /// /// The or null if suitable info detector not found. /// @@ -53,7 +56,8 @@ namespace SixLabors.ImageSharp ///
/// The byte array containing encoded image data to read the header from. /// The format type of the decoded image. - /// Thrown if the stream is not readable. + /// The data is null. + /// The data is not readable. /// /// The or null if suitable info detector not found. /// @@ -65,13 +69,16 @@ namespace SixLabors.ImageSharp /// The configuration. /// The byte array containing encoded image data to read the header from. /// The format type of the decoded image. - /// Thrown if the stream is not readable. + /// The configuration is null. + /// The data is null. + /// The data is not readable. /// /// The or null if suitable info detector is not found. /// public static IImageInfo Identify(Configuration configuration, byte[] data, out IImageFormat format) { - Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(data, nameof(data)); + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Identify(configuration, stream, out format); @@ -82,14 +89,20 @@ namespace SixLabors.ImageSharp /// Load a new instance of from the given encoded byte array. ///
/// The byte array containing image data. + /// The configuration is null. + /// The data is null. /// A new . - public static Image Load(byte[] data) => Load(Configuration.Default, data); + public static Image Load(byte[] data) + => Load(Configuration.Default, data); /// /// Load a new instance of from the given encoded byte array. /// /// The byte array containing encoded image data. /// The pixel format. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(byte[] data) where TPixel : unmanaged, IPixel @@ -101,6 +114,9 @@ namespace SixLabors.ImageSharp /// The byte array containing image data. /// The mime type of the decoded image. /// The pixel format. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(byte[] data, out IImageFormat format) where TPixel : unmanaged, IPixel @@ -112,10 +128,16 @@ namespace SixLabors.ImageSharp /// The configuration options. /// The byte array containing encoded image data. /// The pixel format. + /// The configuration is null. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(Configuration configuration, byte[] data) where TPixel : unmanaged, IPixel { + Guard.NotNull(data, nameof(data)); + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(configuration, stream); @@ -129,10 +151,16 @@ namespace SixLabors.ImageSharp /// The byte array containing encoded image data. /// The of the decoded image. /// The pixel format. + /// The configuration is null. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(Configuration configuration, byte[] data, out IImageFormat format) where TPixel : unmanaged, IPixel { + Guard.NotNull(data, nameof(data)); + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(configuration, stream, out format); @@ -145,10 +173,15 @@ namespace SixLabors.ImageSharp /// The byte array containing encoded image data. /// The decoder. /// The pixel format. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(byte[] data, IImageDecoder decoder) where TPixel : unmanaged, IPixel { + Guard.NotNull(data, nameof(data)); + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(stream, decoder); @@ -162,10 +195,16 @@ namespace SixLabors.ImageSharp /// The byte array containing encoded image data. /// The decoder. /// The pixel format. + /// The configuration is null. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(Configuration configuration, byte[] data, IImageDecoder decoder) where TPixel : unmanaged, IPixel { + Guard.NotNull(data, nameof(data)); + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(configuration, stream, decoder); @@ -173,9 +212,9 @@ namespace SixLabors.ImageSharp } /// - /// By reading the header on the provided byte array this calculates the images format. + /// By reading the header on the provided byte span this calculates the images format. /// - /// The byte array containing encoded image data to read the header from. + /// The byte span containing encoded image data to read the header from. /// The format or null if none found. public static IImageFormat DetectFormat(ReadOnlySpan data) { @@ -183,13 +222,16 @@ namespace SixLabors.ImageSharp } /// - /// By reading the header on the provided byte array this calculates the images format. + /// By reading the header on the provided byte span this calculates the images format. /// /// The configuration. - /// The byte array containing encoded image data to read the header from. + /// The byte span containing encoded image data to read the header from. + /// The configuration is null. /// The mime type or null if none found. public static IImageFormat DetectFormat(Configuration configuration, ReadOnlySpan data) { + Guard.NotNull(configuration, nameof(configuration)); + int maxHeaderSize = configuration.MaxHeaderSize; if (maxHeaderSize <= 0) { @@ -214,28 +256,34 @@ namespace SixLabors.ImageSharp ///
/// The byte span containing encoded image data. /// The pixel format. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(ReadOnlySpan data) where TPixel : unmanaged, IPixel => Load(Configuration.Default, data); /// - /// Load a new instance of from the given encoded byte array. + /// Load a new instance of from the given encoded byte span. /// /// The byte span containing image data. /// The mime type of the decoded image. /// The pixel format. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(ReadOnlySpan data, out IImageFormat format) where TPixel : unmanaged, IPixel => Load(Configuration.Default, data, out format); /// - /// Load a new instance of from the given encoded byte array. + /// Load a new instance of from the given encoded byte span. /// /// The byte span containing encoded image data. /// The decoder. /// The pixel format. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(ReadOnlySpan data, IImageDecoder decoder) where TPixel : unmanaged, IPixel @@ -247,6 +295,9 @@ namespace SixLabors.ImageSharp /// The configuration options. /// The byte span containing encoded image data. /// The pixel format. + /// The configuration is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static unsafe Image Load(Configuration configuration, ReadOnlySpan data) where TPixel : unmanaged, IPixel @@ -267,6 +318,9 @@ namespace SixLabors.ImageSharp /// The byte span containing image data. /// The decoder. /// The pixel format. + /// The configuration is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static unsafe Image Load( Configuration configuration, @@ -290,6 +344,9 @@ namespace SixLabors.ImageSharp /// The byte span containing image data. /// The of the decoded image. /// The pixel format. + /// The configuration is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static unsafe Image Load( Configuration configuration, @@ -311,25 +368,38 @@ namespace SixLabors.ImageSharp ///
/// The byte array containing image data. /// The detected format. + /// The configuration is null. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(byte[] data, out IImageFormat format) => - Load(Configuration.Default, data, out format); + public static Image Load(byte[] data, out IImageFormat format) + => Load(Configuration.Default, data, out format); /// /// Load a new instance of from the given encoded byte array. /// /// The byte array containing encoded image data. /// The decoder. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(byte[] data, IImageDecoder decoder) => Load(Configuration.Default, data, decoder); + public static Image Load(byte[] data, IImageDecoder decoder) + => Load(Configuration.Default, data, decoder); /// /// Load a new instance of from the given encoded byte array. /// /// The configuration for the decoder. /// The byte array containing encoded image data. + /// The configuration is null. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(Configuration configuration, byte[] data) => Load(configuration, data, out _); + public static Image Load(Configuration configuration, byte[] data) + => Load(configuration, data, out _); /// /// Load a new instance of from the given encoded byte array. @@ -337,6 +407,10 @@ namespace SixLabors.ImageSharp /// The configuration for the decoder. /// The byte array containing image data. /// The decoder. + /// The configuration is null. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . public static Image Load(Configuration configuration, byte[] data, IImageDecoder decoder) { @@ -352,6 +426,10 @@ namespace SixLabors.ImageSharp /// The configuration for the decoder. /// The byte array containing image data. /// The mime type of the decoded image. + /// The configuration is null. + /// The data is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . public static Image Load(Configuration configuration, byte[] data, out IImageFormat format) { @@ -365,26 +443,36 @@ namespace SixLabors.ImageSharp /// Load a new instance of from the given encoded byte span. /// /// The byte span containing image data. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(ReadOnlySpan data) => Load(Configuration.Default, data); + public static Image Load(ReadOnlySpan data) + => Load(Configuration.Default, data); /// /// Load a new instance of from the given encoded byte span. /// /// The byte span containing image data. /// The decoder. + /// The data is null. + /// The decoder is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(ReadOnlySpan data, IImageDecoder decoder) => - Load(Configuration.Default, data, decoder); + public static Image Load(ReadOnlySpan data, IImageDecoder decoder) + => Load(Configuration.Default, data, decoder); /// /// Load a new instance of from the given encoded byte array. /// /// The byte span containing image data. /// The detected format. + /// The decoder is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(ReadOnlySpan data, out IImageFormat format) => - Load(Configuration.Default, data, out format); + public static Image Load(ReadOnlySpan data, out IImageFormat format) + => Load(Configuration.Default, data, out format); /// /// Decodes a new instance of from the given encoded byte span. @@ -392,7 +480,8 @@ namespace SixLabors.ImageSharp /// The configuration options. /// The byte span containing image data. /// The . - public static Image Load(Configuration configuration, ReadOnlySpan data) => Load(configuration, data, out _); + public static Image Load(Configuration configuration, ReadOnlySpan data) + => Load(configuration, data, out _); /// /// Load a new instance of from the given encoded byte span. @@ -400,6 +489,11 @@ namespace SixLabors.ImageSharp /// The Configuration. /// The byte span containing image data. /// The decoder. + /// The configuration is null. + /// The decoder is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The . public static unsafe Image Load( Configuration configuration, @@ -421,6 +515,9 @@ namespace SixLabors.ImageSharp /// The configuration options. /// The byte span containing image data. /// The of the decoded image.> + /// The configuration is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . public static unsafe Image Load( Configuration configuration, diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index 1a9fa15462..8546dd2700 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -19,19 +19,19 @@ namespace SixLabors.ImageSharp /// The image file to open and to read the header from. /// The mime type or null if none found. public static IImageFormat DetectFormat(string filePath) - { - return DetectFormat(Configuration.Default, filePath); - } + => DetectFormat(Configuration.Default, filePath); /// /// By reading the header on the provided file this calculates the images mime type. /// /// The configuration. /// The image file to open and to read the header from. + /// The configuration is null. /// The mime type or null if none found. public static IImageFormat DetectFormat(Configuration configuration, string filePath) { Guard.NotNull(configuration, nameof(configuration)); + using (Stream file = configuration.FileSystem.OpenRead(filePath)) { return DetectFormat(configuration, file); @@ -42,22 +42,22 @@ namespace SixLabors.ImageSharp /// Reads the raw image information from the specified stream without fully decoding it. /// /// The image file to open and to read the header from. - /// Thrown if the stream is not readable. /// /// The or null if suitable info detector not found. /// - public static IImageInfo Identify(string filePath) => Identify(filePath, out IImageFormat _); + public static IImageInfo Identify(string filePath) + => Identify(filePath, out IImageFormat _); /// /// Reads the raw image information from the specified stream without fully decoding it. /// /// The image file to open and to read the header from. /// The format type of the decoded image. - /// Thrown if the stream is not readable. /// /// The or null if suitable info detector not found. /// - public static IImageInfo Identify(string filePath, out IImageFormat format) => Identify(Configuration.Default, filePath, out format); + public static IImageInfo Identify(string filePath, out IImageFormat format) + => Identify(Configuration.Default, filePath, out format); /// /// Reads the raw image information from the specified stream without fully decoding it. @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp /// The configuration. /// The image file to open and to read the header from. /// The format type of the decoded image. - /// Thrown if the stream is not readable. + /// The configuration is null. /// /// The or null if suitable info detector is not found. /// @@ -86,7 +86,8 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is not readable nor seekable. /// /// The . - public static Image Load(string path) => Load(Configuration.Default, path); + public static Image Load(string path) + => Load(Configuration.Default, path); /// /// Create a new instance of the class from the given file. @@ -97,18 +98,21 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is not readable nor seekable. /// /// A new . - public static Image Load(string path, out IImageFormat format) => Load(Configuration.Default, path, out format); + public static Image Load(string path, out IImageFormat format) + => Load(Configuration.Default, path, out format); /// /// Create a new instance of the class from the given file. /// /// The configuration for the decoder. /// The file path to the image. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The configuration is null. + /// The path is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(Configuration configuration, string path) => Load(configuration, path, out _); + public static Image Load(Configuration configuration, string path) + => Load(configuration, path, out _); /// /// Create a new instance of the class from the given file. @@ -116,13 +120,17 @@ namespace SixLabors.ImageSharp /// The Configuration. /// The file path to the image. /// The decoder. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The configuration is null. + /// The path is null. + /// The decoder is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . public static Image Load(Configuration configuration, string path, IImageDecoder decoder) { Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(path, nameof(path)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { return Load(configuration, stream, decoder); @@ -134,57 +142,58 @@ namespace SixLabors.ImageSharp /// /// The file path to the image. /// The decoder. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The path is null. + /// The decoder is null. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(string path, IImageDecoder decoder) => Load(Configuration.Default, path, decoder); + public static Image Load(string path, IImageDecoder decoder) + => Load(Configuration.Default, path, decoder); /// /// Create a new instance of the class from the given file. /// /// The file path to the image. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The path is null. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new . public static Image Load(string path) where TPixel : unmanaged, IPixel - { - return Load(Configuration.Default, path); - } + => Load(Configuration.Default, path); /// /// Create a new instance of the class from the given file. /// /// The file path to the image. /// The mime type of the decoded image. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The path is null. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new . public static Image Load(string path, out IImageFormat format) where TPixel : unmanaged, IPixel - { - return Load(Configuration.Default, path, out format); - } + => Load(Configuration.Default, path, out format); /// /// Create a new instance of the class from the given file. /// /// The configuration options. /// The file path to the image. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The configuration is null. + /// The path is null. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new . public static Image Load(Configuration configuration, string path) where TPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(path, nameof(path)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { return Load(configuration, stream); @@ -197,15 +206,18 @@ namespace SixLabors.ImageSharp /// The configuration options. /// The file path to the image. /// The mime type of the decoded image. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The configuration is null. + /// The path is null. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new . public static Image Load(Configuration configuration, string path, out IImageFormat format) where TPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(path, nameof(path)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { return Load(configuration, stream, out format); @@ -219,13 +231,16 @@ namespace SixLabors.ImageSharp /// The configuration options. /// The file path to the image. /// The mime type of the decoded image. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The configuration is null. + /// The path is null. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(Configuration configuration, string path, out IImageFormat format) { Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(path, nameof(path)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { return Load(configuration, stream, out format); @@ -237,16 +252,14 @@ namespace SixLabors.ImageSharp /// /// The file path to the image. /// The decoder. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The path is null. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new . public static Image Load(string path, IImageDecoder decoder) where TPixel : unmanaged, IPixel - { - return Load(Configuration.Default, path, decoder); - } + => Load(Configuration.Default, path, decoder); /// /// Create a new instance of the class from the given file. @@ -254,15 +267,19 @@ namespace SixLabors.ImageSharp /// The Configuration. /// The file path to the image. /// The decoder. - /// - /// Thrown if the stream is not readable nor seekable. - /// + /// The configuration is null. + /// The path is null. + /// The decoder is null. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new . public static Image Load(Configuration configuration, string path, IImageDecoder decoder) where TPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(path, nameof(path)); + using (Stream stream = configuration.FileSystem.OpenRead(path)) { return Load(configuration, stream, decoder); diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 52d71409bb..332ca471e9 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -19,16 +19,20 @@ namespace SixLabors.ImageSharp /// By reading the header on the provided stream this calculates the images format type. /// /// The image stream to read the header from. - /// Thrown if the stream is not readable. + /// The stream is null. + /// The stream is not readable. /// The format type or null if none found. - public static IImageFormat DetectFormat(Stream stream) => DetectFormat(Configuration.Default, stream); + public static IImageFormat DetectFormat(Stream stream) + => DetectFormat(Configuration.Default, stream); /// /// By reading the header on the provided stream this calculates the images format type. /// /// The configuration. /// The image stream to read the header from. - /// Thrown if the stream is not readable. + /// The configuration is null. + /// The stream is null. + /// The stream is not readable. /// The format type or null if none found. public static IImageFormat DetectFormat(Configuration configuration, Stream stream) => WithSeekableStream(configuration, stream, s => InternalDetectFormat(s, configuration)); @@ -37,22 +41,28 @@ namespace SixLabors.ImageSharp /// Reads the raw image information from the specified stream without fully decoding it. /// /// The image stream to read the header from. - /// Thrown if the stream is not readable. + /// The stream is null. + /// The stream is not readable. + /// Image contains invalid content. /// /// The or null if suitable info detector not found. /// - public static IImageInfo Identify(Stream stream) => Identify(stream, out IImageFormat _); + public static IImageInfo Identify(Stream stream) + => Identify(stream, out IImageFormat _); /// /// Reads the raw image information from the specified stream without fully decoding it. /// /// The image stream to read the header from. /// The format type of the decoded image. - /// Thrown if the stream is not readable. + /// The stream is null. + /// The stream is not readable. + /// Image contains invalid content. /// /// The or null if suitable info detector not found. /// - public static IImageInfo Identify(Stream stream, out IImageFormat format) => Identify(Configuration.Default, stream, out format); + public static IImageInfo Identify(Stream stream, out IImageFormat format) + => Identify(Configuration.Default, stream, out format); /// /// Reads the raw image information from the specified stream without fully decoding it. @@ -60,7 +70,10 @@ namespace SixLabors.ImageSharp /// The configuration. /// The image stream to read the information from. /// The format type of the decoded image. - /// Thrown if the stream is not readable. + /// The configuration is null. + /// The stream is null. + /// The stream is not readable. + /// Image contains invalid content. /// /// The or null if suitable info detector is not found. /// @@ -78,18 +91,23 @@ namespace SixLabors.ImageSharp /// /// The stream containing image information. /// The format type of the decoded image. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(Stream stream, out IImageFormat format) => Load(Configuration.Default, stream, out format); + public static Image Load(Stream stream, out IImageFormat format) + => Load(Configuration.Default, stream, out format); /// /// Decode a new instance of the class from the given stream. /// The pixel format is selected by the decoder. /// /// The stream containing image information. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The . public static Image Load(Stream stream) => Load(Configuration.Default, stream); @@ -99,10 +117,14 @@ namespace SixLabors.ImageSharp /// /// The stream containing image information. /// The decoder. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The stream is null. + /// The decoder is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The . - public static Image Load(Stream stream, IImageDecoder decoder) => Load(Configuration.Default, stream, decoder); + public static Image Load(Stream stream, IImageDecoder decoder) + => Load(Configuration.Default, stream, decoder); /// /// Decode a new instance of the class from the given stream. @@ -111,19 +133,29 @@ namespace SixLabors.ImageSharp /// The configuration for the decoder. /// The stream containing image information. /// The decoder. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The configuration is null. + /// The stream is null. + /// The decoder is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// A new .> - public static Image Load(Configuration configuration, Stream stream, IImageDecoder decoder) => - WithSeekableStream(configuration, stream, s => decoder.Decode(configuration, s)); + public static Image Load(Configuration configuration, Stream stream, IImageDecoder decoder) + { + Guard.NotNull(decoder, nameof(decoder)); + return WithSeekableStream(configuration, stream, s => decoder.Decode(configuration, s)); + } /// /// Decode a new instance of the class from the given stream. /// /// The configuration for the decoder. /// The stream containing image information. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The configuration is null. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// A new .> public static Image Load(Configuration configuration, Stream stream) => Load(configuration, stream, out _); @@ -131,8 +163,10 @@ namespace SixLabors.ImageSharp /// Create a new instance of the class from the given stream. /// /// The stream containing image information. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new .> public static Image Load(Stream stream) @@ -144,8 +178,10 @@ namespace SixLabors.ImageSharp ///
/// The stream containing image information. /// The format type of the decoded image. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new .> public static Image Load(Stream stream, out IImageFormat format) @@ -157,8 +193,10 @@ namespace SixLabors.ImageSharp ///
/// The stream containing image information. /// The decoder. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new .> public static Image Load(Stream stream, IImageDecoder decoder) @@ -171,8 +209,11 @@ namespace SixLabors.ImageSharp /// The Configuration. /// The stream containing image information. /// The decoder. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The configuration is null. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new .> public static Image Load(Configuration configuration, Stream stream, IImageDecoder decoder) @@ -184,8 +225,11 @@ namespace SixLabors.ImageSharp ///
/// The configuration options. /// The stream containing image information. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The configuration is null. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new .> public static Image Load(Configuration configuration, Stream stream) @@ -198,14 +242,16 @@ namespace SixLabors.ImageSharp /// The configuration options. /// The stream containing image information. /// The format type of the decoded image. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The configuration is null. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// The pixel format. /// A new . public static Image Load(Configuration configuration, Stream stream, out IImageFormat format) where TPixel : unmanaged, IPixel { - Guard.NotNull(configuration, nameof(configuration)); (Image img, IImageFormat format) data = WithSeekableStream(configuration, stream, s => Decode(s, configuration)); format = data.format; @@ -220,7 +266,7 @@ namespace SixLabors.ImageSharp foreach (KeyValuePair val in configuration.ImageFormatsManager.ImageDecoders) { - sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); + sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine); } throw new UnknownImageFormatException(sb.ToString()); @@ -233,12 +279,14 @@ namespace SixLabors.ImageSharp /// The configuration options. /// The stream containing image information. /// The format type of the decoded image. - /// Thrown if the stream is not readable. - /// Image cannot be loaded. + /// The configuration is null. + /// The stream is null. + /// The stream is not readable. + /// Image format not recognised. + /// Image contains invalid content. /// A new . public static Image Load(Configuration configuration, Stream stream, out IImageFormat format) { - Guard.NotNull(configuration, nameof(configuration)); (Image img, IImageFormat format) data = WithSeekableStream(configuration, stream, s => Decode(s, configuration)); format = data.format; @@ -253,7 +301,7 @@ namespace SixLabors.ImageSharp foreach (KeyValuePair val in configuration.ImageFormatsManager.ImageDecoders) { - sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); + sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine); } throw new UnknownImageFormatException(sb.ToString()); @@ -261,6 +309,9 @@ namespace SixLabors.ImageSharp private static T WithSeekableStream(Configuration configuration, Stream stream, Func action) { + Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(stream, nameof(stream)); + if (!stream.CanRead) { throw new NotSupportedException("Cannot read from the stream."); diff --git a/src/ImageSharp/Image.LoadPixelData.cs b/src/ImageSharp/Image.LoadPixelData.cs index f8f2e84850..f36243cc3e 100644 --- a/src/ImageSharp/Image.LoadPixelData.cs +++ b/src/ImageSharp/Image.LoadPixelData.cs @@ -1,9 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -21,6 +20,7 @@ namespace SixLabors.ImageSharp /// The width of the final image. /// The height of the final image. /// The pixel format. + /// The data length is incorrect. /// A new . public static Image LoadPixelData(TPixel[] data, int width, int height) where TPixel : unmanaged, IPixel @@ -33,6 +33,7 @@ namespace SixLabors.ImageSharp /// The width of the final image. /// The height of the final image. /// The pixel format. + /// The data length is incorrect. /// A new . public static Image LoadPixelData(ReadOnlySpan data, int width, int height) where TPixel : unmanaged, IPixel @@ -45,6 +46,7 @@ namespace SixLabors.ImageSharp /// The width of the final image. /// The height of the final image. /// The pixel format. + /// The data length is incorrect. /// A new . public static Image LoadPixelData(byte[] data, int width, int height) where TPixel : unmanaged, IPixel @@ -57,6 +59,7 @@ namespace SixLabors.ImageSharp /// The width of the final image. /// The height of the final image. /// The pixel format. + /// The data length is incorrect. /// A new . public static Image LoadPixelData(ReadOnlySpan data, int width, int height) where TPixel : unmanaged, IPixel @@ -65,60 +68,68 @@ namespace SixLabors.ImageSharp /// /// Create a new instance of the class from the given byte array in format. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The byte array containing image data. /// The width of the final image. /// The height of the final image. /// The pixel format. + /// The configuration is null. + /// The data length is incorrect. /// A new . - public static Image LoadPixelData(Configuration config, byte[] data, int width, int height) + public static Image LoadPixelData(Configuration configuration, byte[] data, int width, int height) where TPixel : unmanaged, IPixel - => LoadPixelData(config, MemoryMarshal.Cast(new ReadOnlySpan(data)), width, height); + => LoadPixelData(configuration, MemoryMarshal.Cast(new ReadOnlySpan(data)), width, height); /// /// Create a new instance of the class from the given byte array in format. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The byte array containing image data. /// The width of the final image. /// The height of the final image. /// The pixel format. + /// The configuration is null. + /// The data length is incorrect. /// A new . - public static Image LoadPixelData(Configuration config, ReadOnlySpan data, int width, int height) + public static Image LoadPixelData(Configuration configuration, ReadOnlySpan data, int width, int height) where TPixel : unmanaged, IPixel - => LoadPixelData(config, MemoryMarshal.Cast(data), width, height); + => LoadPixelData(configuration, MemoryMarshal.Cast(data), width, height); /// /// Create a new instance of the class from the raw data. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The Span containing the image Pixel data. /// The width of the final image. /// The height of the final image. /// The pixel format. + /// The configuration is null. + /// The data length is incorrect. /// A new . - public static Image LoadPixelData(Configuration config, TPixel[] data, int width, int height) + public static Image LoadPixelData(Configuration configuration, TPixel[] data, int width, int height) where TPixel : unmanaged, IPixel - { - return LoadPixelData(config, new ReadOnlySpan(data), width, height); - } + => LoadPixelData(configuration, new ReadOnlySpan(data), width, height); /// /// Create a new instance of the class from the raw data. /// - /// The config for the decoder. + /// The configuration for the decoder. /// The Span containing the image Pixel data. /// The width of the final image. /// The height of the final image. + /// The configuration is null. + /// The data length is incorrect. /// The pixel format. /// A new . - public static Image LoadPixelData(Configuration config, ReadOnlySpan data, int width, int height) + public static Image LoadPixelData(Configuration configuration, ReadOnlySpan data, int width, int height) where TPixel : unmanaged, IPixel { + Guard.NotNull(configuration, nameof(configuration)); + int count = width * height; Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data)); - var image = new Image(config, width, height); + var image = new Image(configuration, width, height); data = data.Slice(0, count); data.CopyTo(image.Frames.RootFrame.PixelBuffer.FastMemoryGroup); diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index e5181a0db3..0dd8c814d0 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -20,22 +20,27 @@ namespace SixLabors.ImageSharp /// allowing to view/manipulate it as an ImageSharp instance. ///
/// The pixel type - /// The + /// The /// The pixel memory. /// The width of the memory image. /// The height of the memory image. /// The . + /// The configuration is null. + /// The metadata is null. /// An instance public static Image WrapMemory( - Configuration config, + Configuration configuration, Memory pixelMemory, int width, int height, ImageMetadata metadata) where TPixel : unmanaged, IPixel { + Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(metadata, nameof(metadata)); + var memorySource = MemoryGroup.Wrap(pixelMemory); - return new Image(config, memorySource, width, height, metadata); + return new Image(configuration, memorySource, width, height, metadata); } /// @@ -43,20 +48,19 @@ namespace SixLabors.ImageSharp /// allowing to view/manipulate it as an ImageSharp instance. /// /// The pixel type - /// The + /// The /// The pixel memory. /// The width of the memory image. /// The height of the memory image. + /// The configuration is null. /// An instance. public static Image WrapMemory( - Configuration config, + Configuration configuration, Memory pixelMemory, int width, int height) where TPixel : unmanaged, IPixel - { - return WrapMemory(config, pixelMemory, width, height, new ImageMetadata()); - } + => WrapMemory(configuration, pixelMemory, width, height, new ImageMetadata()); /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, @@ -73,9 +77,7 @@ namespace SixLabors.ImageSharp int width, int height) where TPixel : unmanaged, IPixel - { - return WrapMemory(Configuration.Default, pixelMemory, width, height); - } + => WrapMemory(Configuration.Default, pixelMemory, width, height); /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, @@ -85,22 +87,27 @@ namespace SixLabors.ImageSharp /// It will be disposed together with the result image. /// /// The pixel type - /// The + /// The /// The that is being transferred to the image /// The width of the memory image. /// The height of the memory image. /// The + /// The configuration is null. + /// The metadata is null. /// An instance public static Image WrapMemory( - Configuration config, + Configuration configuration, IMemoryOwner pixelMemoryOwner, int width, int height, ImageMetadata metadata) where TPixel : unmanaged, IPixel { + Guard.NotNull(configuration, nameof(configuration)); + Guard.NotNull(metadata, nameof(metadata)); + var memorySource = MemoryGroup.Wrap(pixelMemoryOwner); - return new Image(config, memorySource, width, height, metadata); + return new Image(configuration, memorySource, width, height, metadata); } /// @@ -111,20 +118,19 @@ namespace SixLabors.ImageSharp /// It will be disposed together with the result image. /// /// The pixel type. - /// The + /// The /// The that is being transferred to the image. /// The width of the memory image. /// The height of the memory image. + /// The configuration is null. /// An instance public static Image WrapMemory( - Configuration config, + Configuration configuration, IMemoryOwner pixelMemoryOwner, int width, int height) where TPixel : unmanaged, IPixel - { - return WrapMemory(config, pixelMemoryOwner, width, height, new ImageMetadata()); - } + => WrapMemory(configuration, pixelMemoryOwner, width, height, new ImageMetadata()); /// /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, @@ -143,8 +149,6 @@ namespace SixLabors.ImageSharp int width, int height) where TPixel : unmanaged, IPixel - { - return WrapMemory(Configuration.Default, pixelMemoryOwner, width, height); - } + => WrapMemory(Configuration.Default, pixelMemoryOwner, width, height); } } From 0b2d95196f9a187e49a8afdeb56223806c6ef2d6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 21 Apr 2020 20:18:26 +0100 Subject: [PATCH 143/213] Document Mutate and Clone --- .../Extensions/ProcessingExtensions.cs | 67 +++++++++++++++++-- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs index 59be5bf02c..45cff93982 100644 --- a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs @@ -19,6 +19,10 @@ namespace SixLabors.ImageSharp.Processing /// /// The image to mutate. /// The operation to perform on the source. + /// The source is null. + /// The operation is null. + /// The source has been disposed. + /// The processing operation failed. public static void Mutate(this Image source, Action operation) => Mutate(source, source.GetConfiguration(), operation); @@ -28,6 +32,11 @@ namespace SixLabors.ImageSharp.Processing /// The image to mutate. /// The configuration which allows altering default behaviour or extending the library. /// The operation to perform on the source. + /// The configuration is null. + /// The source is null. + /// The operation is null. + /// The source has been disposed. + /// The processing operation failed. public static void Mutate(this Image source, Configuration configuration, Action operation) { Guard.NotNull(configuration, nameof(configuration)); @@ -44,6 +53,10 @@ namespace SixLabors.ImageSharp.Processing /// The pixel format. /// The image to mutate. /// The operation to perform on the source. + /// The source is null. + /// The operation is null. + /// The source has been disposed. + /// The processing operation failed. public static void Mutate(this Image source, Action operation) where TPixel : unmanaged, IPixel => Mutate(source, source.GetConfiguration(), operation); @@ -55,6 +68,11 @@ namespace SixLabors.ImageSharp.Processing /// The image to mutate. /// The configuration which allows altering default behaviour or extending the library. /// The operation to perform on the source. + /// The configuration is null. + /// The source is null. + /// The operation is null. + /// The source has been disposed. + /// The processing operation failed. public static void Mutate(this Image source, Configuration configuration, Action operation) where TPixel : unmanaged, IPixel { @@ -75,6 +93,10 @@ namespace SixLabors.ImageSharp.Processing /// The pixel format. /// The image to mutate. /// The operations to perform on the source. + /// The source is null. + /// The operations are null. + /// The source has been disposed. + /// The processing operation failed. public static void Mutate(this Image source, params IImageProcessor[] operations) where TPixel : unmanaged, IPixel => Mutate(source, source.GetConfiguration(), operations); @@ -86,6 +108,11 @@ namespace SixLabors.ImageSharp.Processing /// The image to mutate. /// The configuration which allows altering default behaviour or extending the library. /// The operations to perform on the source. + /// The configuration is null. + /// The source is null. + /// The operations are null. + /// The source has been disposed. + /// The processing operation failed. public static void Mutate(this Image source, Configuration configuration, params IImageProcessor[] operations) where TPixel : unmanaged, IPixel { @@ -104,7 +131,11 @@ namespace SixLabors.ImageSharp.Processing /// /// The image to clone. /// The operation to perform on the clone. - /// The new . + /// The new . + /// The source is null. + /// The operation is null. + /// The source has been disposed. + /// The processing operation failed. public static Image Clone(this Image source, Action operation) => Clone(source, source.GetConfiguration(), operation); @@ -114,7 +145,12 @@ namespace SixLabors.ImageSharp.Processing /// The image to clone. /// The configuration which allows altering default behaviour or extending the library. /// The operation to perform on the clone. - /// The new . + /// The configuration is null. + /// The source is null. + /// The operation is null. + /// The source has been disposed. + /// The processing operation failed. + /// The new . public static Image Clone(this Image source, Configuration configuration, Action operation) { Guard.NotNull(configuration, nameof(configuration)); @@ -133,7 +169,11 @@ namespace SixLabors.ImageSharp.Processing /// The pixel format. /// The image to clone. /// The operation to perform on the clone. - /// The new + /// The source is null. + /// The operation is null. + /// The source has been disposed. + /// The processing operation failed. + /// The new . public static Image Clone(this Image source, Action operation) where TPixel : unmanaged, IPixel => Clone(source, source.GetConfiguration(), operation); @@ -145,7 +185,12 @@ namespace SixLabors.ImageSharp.Processing /// The image to clone. /// The configuration which allows altering default behaviour or extending the library. /// The operation to perform on the clone. - /// The new + /// The configuration is null. + /// The source is null. + /// The operation is null. + /// The source has been disposed. + /// The processing operation failed. + /// The new public static Image Clone(this Image source, Configuration configuration, Action operation) where TPixel : unmanaged, IPixel { @@ -167,7 +212,11 @@ namespace SixLabors.ImageSharp.Processing /// The pixel format. /// The image to clone. /// The operations to perform on the clone. - /// The new + /// The source is null. + /// The operations are null. + /// The source has been disposed. + /// The processing operation failed. + /// The new public static Image Clone(this Image source, params IImageProcessor[] operations) where TPixel : unmanaged, IPixel => Clone(source, source.GetConfiguration(), operations); @@ -179,7 +228,12 @@ namespace SixLabors.ImageSharp.Processing /// The image to clone. /// The configuration which allows altering default behaviour or extending the library. /// The operations to perform on the clone. - /// The new + /// The configuration is null. + /// The source is null. + /// The operations are null. + /// The source has been disposed. + /// The processing operation failed. + /// The new public static Image Clone(this Image source, Configuration configuration, params IImageProcessor[] operations) where TPixel : unmanaged, IPixel { @@ -200,6 +254,7 @@ namespace SixLabors.ImageSharp.Processing ///
/// The image processing context. /// The operations to perform on the source. + /// The processing operation failed. /// The to allow chaining of operations. public static IImageProcessingContext ApplyProcessors( this IImageProcessingContext source, From 77ccc3bb89131bbd9b3714e5ea47d572a66532f5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 21 Apr 2020 20:32:27 +0100 Subject: [PATCH 144/213] Document save, make params consistant --- src/ImageSharp/ImageExtensions.cs | 46 ++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 62ac449b72..e5b2a32a99 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -7,12 +7,11 @@ using System.IO; using System.Text; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp { /// - /// Extension methods over Image{TPixel}. + /// Extension methods for the type. /// public static partial class ImageExtensions { @@ -20,13 +19,13 @@ namespace SixLabors.ImageSharp /// Writes the image to the given stream using the currently loaded image format. ///
/// The source image. - /// The file path to save the image to. - /// Thrown if the stream is null. - public static void Save(this Image source, string filePath) + /// The file path to save the image to. + /// The path is null. + public static void Save(this Image source, string path) { - Guard.NotNullOrWhiteSpace(filePath, nameof(filePath)); + Guard.NotNull(path, nameof(path)); - string ext = Path.GetExtension(filePath); + string ext = Path.GetExtension(path); IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); if (format is null) { @@ -34,7 +33,7 @@ namespace SixLabors.ImageSharp sb.AppendLine($"No encoder was found for extension '{ext}'. Registered encoders include:"); foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) { - sb.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); + sb.AppendFormat(" - {0} : {1}{2}", fmt.Name, string.Join(", ", fmt.FileExtensions), Environment.NewLine); } throw new NotSupportedException(sb.ToString()); @@ -48,26 +47,28 @@ namespace SixLabors.ImageSharp sb.AppendLine($"No encoder was found for extension '{ext}' using image format '{format.Name}'. Registered encoders include:"); foreach (KeyValuePair enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders) { - sb.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); + sb.AppendFormat(" - {0} : {1}{2}", enc.Key, enc.Value.GetType().Name, Environment.NewLine); } throw new NotSupportedException(sb.ToString()); } - source.Save(filePath, encoder); + source.Save(path, encoder); } /// /// Writes the image to the given stream using the currently loaded image format. /// /// The source image. - /// The file path to save the image to. + /// The file path to save the image to. /// The encoder to save the image with. - /// Thrown if the encoder is null. - public static void Save(this Image source, string filePath, IImageEncoder encoder) + /// The path is null. + /// The encoder is null. + public static void Save(this Image source, string path, IImageEncoder encoder) { + Guard.NotNull(path, nameof(path)); Guard.NotNull(encoder, nameof(encoder)); - using (Stream fs = source.GetConfiguration().FileSystem.Create(filePath)) + using (Stream fs = source.GetConfiguration().FileSystem.Create(path)) { source.Save(fs, encoder); } @@ -79,10 +80,20 @@ namespace SixLabors.ImageSharp /// The source image. /// The stream to save the image to. /// The format to save the image in. - /// Thrown if the stream is null. + /// The stream is null. + /// The format is null. + /// The stream is not writable. + /// No encoder available for provided format. public static void Save(this Image source, Stream stream, IImageFormat format) { + Guard.NotNull(stream, nameof(stream)); Guard.NotNull(format, nameof(format)); + + if (!stream.CanWrite) + { + throw new NotSupportedException("Cannot write to the stream."); + } + IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); if (encoder is null) @@ -92,7 +103,7 @@ namespace SixLabors.ImageSharp foreach (KeyValuePair val in source.GetConfiguration().ImageFormatsManager.ImageEncoders) { - sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); + sb.AppendFormat(" - {0} : {1}{2}", val.Key.Name, val.Value.GetType().Name, Environment.NewLine); } throw new NotSupportedException(sb.ToString()); @@ -113,9 +124,12 @@ namespace SixLabors.ImageSharp ///
/// The source image /// The format. + /// The format is null. /// The public static string ToBase64String(this Image source, IImageFormat format) { + Guard.NotNull(format, nameof(format)); + using var stream = new MemoryStream(); source.Save(stream, format); From 7ef02eba1f5b0c43d5fbbed1c7ecce60a88aaf55 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 21 Apr 2020 20:53:40 +0100 Subject: [PATCH 145/213] Update tests --- tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs | 4 ++-- .../ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs | 4 ++-- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index a8376f51b9..85cdf6d11a 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -394,10 +394,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp [Theory] [WithFile(InvalidPaletteSize, PixelTypes.Rgba32)] - public void BmpDecoder_ThrowsImageFormatException_OnInvalidPaletteSize(TestImageProvider provider) + public void BmpDecoder_ThrowsInvalidImageContentException_OnInvalidPaletteSize(TestImageProvider provider) where TPixel : unmanaged, IPixel { - Assert.Throws(() => + Assert.Throws(() => { using (provider.GetImage(BmpDecoder)) { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs index cf2e5c81b3..57051a9d7b 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [Theory] [WithFileCollection(nameof(UnrecoverableTestJpegs), PixelTypes.Rgba32)] - public void UnrecoverableImage_Throws_ImageFormatException(TestImageProvider provider) - where TPixel : unmanaged, IPixel => Assert.Throws(provider.GetImage); + public void UnrecoverableImage_Throws_InvalidImageContentException(TestImageProvider provider) + where TPixel : unmanaged, IPixel => Assert.Throws(provider.GetImage); } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index ee4001c203..297512fa6a 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png var decoder = new PngDecoder(); ImageFormatException exception = - Assert.Throws(() => decoder.Decode(null, memStream)); + Assert.Throws(() => decoder.Decode(null, memStream)); Assert.Equal($"CRC Error. PNG {chunkName} chunk is corrupt!", exception.Message); } From 8a83c5e98c5d1c7878023d24aa477d9a627fd220 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 21 Apr 2020 23:39:26 +0100 Subject: [PATCH 146/213] Cast to long and add test/guard. Fix #1167 --- src/ImageSharp/Memory/Buffer2D{T}.cs | 4 ++-- .../Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs | 8 +++++++- .../Memory/DiscontiguousBuffers/MemoryGroupTests.cs | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index bf8630931a..ada1d29b6d 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.Memory { DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y)); DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); - return this.FastMemoryGroup.View.GetBoundedSlice(y * this.Width, this.Width); + return this.FastMemoryGroup.View.GetBoundedSlice(y * (long)this.Width, this.Width); } /// @@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Memory } [MethodImpl(InliningOptions.ColdPath)] - private Memory GetRowMemorySlow(int y) => this.FastMemoryGroup.GetBoundedSlice(y * this.Width, this.Width); + private Memory GetRowMemorySlow(int y) => this.FastMemoryGroup.GetBoundedSlice(y * (long)this.Width, this.Width); [MethodImpl(InliningOptions.ColdPath)] private Memory GetSingleMemorySlow() => this.FastMemoryGroup.Single(); diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs index 28da49263e..295f9190a9 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -38,6 +38,12 @@ namespace SixLabors.ImageSharp.Memory Guard.MustBeLessThan(start, group.TotalLength, nameof(start)); int bufferIdx = (int)(start / group.BufferLength); + + if (bufferIdx < 0) + { + throw new ArgumentOutOfRangeException(nameof(start)); + } + if (bufferIdx >= group.Count) { throw new ArgumentOutOfRangeException(nameof(start)); diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs index 2a5dafb27d..15b07265f6 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs @@ -152,6 +152,7 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers public static TheoryData GetBoundedSlice_ErrorData = new TheoryData() { + { 300, 100, -1, 91 }, { 300, 100, 110, 91 }, { 42, 7, 0, 8 }, { 42, 7, 1, 7 }, From 8738afe816869fbced855cc4ae3a629009829979 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 22 Apr 2020 09:01:19 +0100 Subject: [PATCH 147/213] fix configuration param names --- .../GraphicOptionsDefaultsExtensions.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs index 10909c4f31..c8beea8e85 100644 --- a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs +++ b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs @@ -28,13 +28,13 @@ namespace SixLabors.ImageSharp /// /// Sets the default options against the configuration. /// - /// The image processing context to store default against. + /// The configuration to store default against. /// The default options to use. - public static void SetGraphicsOptions(this Configuration context, Action optionsBuilder) + public static void SetGraphicsOptions(this Configuration configuration, Action optionsBuilder) { - var cloned = context.GetGraphicsOptions().DeepClone(); + var cloned = configuration.GetGraphicsOptions().DeepClone(); optionsBuilder(cloned); - context.Properties[typeof(GraphicsOptions)] = cloned; + configuration.Properties[typeof(GraphicsOptions)] = cloned; } /// @@ -52,11 +52,11 @@ namespace SixLabors.ImageSharp /// /// Sets the default options against the configuration. /// - /// The image processing context to store default against. + /// The configuration to store default against. /// The default options to use. - public static void SetGraphicsOptions(this Configuration context, GraphicsOptions options) + public static void SetGraphicsOptions(this Configuration configuration, GraphicsOptions options) { - context.Properties[typeof(GraphicsOptions)] = options; + configuration.Properties[typeof(GraphicsOptions)] = options; } /// @@ -81,11 +81,11 @@ namespace SixLabors.ImageSharp /// /// Gets the default options against the image processing context. /// - /// The image processing context to retrieve defaults from. + /// The configuration to retrieve defaults from. /// The globaly configued default options. - public static GraphicsOptions GetGraphicsOptions(this Configuration context) + public static GraphicsOptions GetGraphicsOptions(this Configuration configuration) { - if (context.Properties.TryGetValue(typeof(GraphicsOptions), out var options) && options is GraphicsOptions go) + if (configuration.Properties.TryGetValue(typeof(GraphicsOptions), out var options) && options is GraphicsOptions go) { return go; } @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp var configOptions = new GraphicsOptions(); // capture the fallback so the same instance will always be returned in case its mutated - context.Properties[typeof(GraphicsOptions)] = configOptions; + configuration.Properties[typeof(GraphicsOptions)] = configOptions; return configOptions; } } From d38764dba2cbcf68b25778a304b5ab2b794b3754 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 22 Apr 2020 09:02:03 +0100 Subject: [PATCH 148/213] remove explicit backing fields for property bags --- src/ImageSharp/Configuration.cs | 4 +--- .../Processing/DefaultImageProcessorContext{TPixel}.cs | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index b2d819f1c0..17ac8c3fd8 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -28,8 +28,6 @@ namespace SixLabors.ImageSharp private int maxDegreeOfParallelism = Environment.ProcessorCount; - private Dictionary properties = new Dictionary(); - /// /// Initializes a new instance of the class. /// @@ -80,7 +78,7 @@ namespace SixLabors.ImageSharp /// Gets a set of properties for the Congiguration. /// /// This can be used for storing global settings and defaults to be accessable to processors. - public IDictionary Properties => this.properties; + public IDictionary Properties { get; } = new Dictionary(); /// /// Gets the currently registered s. diff --git a/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs b/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs index 5ee3f6483d..714a45f5f0 100644 --- a/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs +++ b/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs @@ -16,7 +16,6 @@ namespace SixLabors.ImageSharp.Processing { private readonly bool mutate; private readonly Image source; - private readonly Dictionary properties = new Dictionary(); private Image destination; /// @@ -42,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing public Configuration Configuration { get; } /// - public IDictionary Properties => this.properties; + public IDictionary Properties { get; } = new Dictionary(); /// public Image GetResultImage() From 9eaeecfae9769094a6636861f064ee9f2932c6f6 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 22 Apr 2020 12:17:33 +0200 Subject: [PATCH 149/213] Add tests for setting iptc value with strict option disabled --- .../Metadata/Profiles/IPTC/IptcProfile.cs | 2 +- .../Profiles/IPTC/IptcProfileTests.cs | 36 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index 9206e43771..f138cc650f 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc public IptcProfile DeepClone() => new IptcProfile(this); /// - /// Returns all value with the specified tag. + /// Returns all values with the specified tag. /// /// The tag of the iptc value. /// The values found with the specified tag. diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index d9f44cef9c..3baea45d62 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -25,8 +25,8 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC } [Theory] - [MemberData("AllIptcTags")] - public void IptcProfile_SetValue_WithStrictOption_Works(IptcTag tag) + [MemberData(nameof(AllIptcTags))] + public void IptcProfile_SetValue_WithStrictEnabled_Works(IptcTag tag) { // arrange var profile = new IptcProfile(); @@ -41,6 +41,23 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC Assert.Equal(expectedLength, actual.Value.Length); } + [Theory] + [MemberData(nameof(AllIptcTags))] + public void IptcProfile_SetValue_WithStrictDisabled_Works(IptcTag tag) + { + // arrange + var profile = new IptcProfile(); + var value = new string('s', tag.MaxLength() + 1); + var expectedLength = value.Length; + + // act + profile.SetValue(tag, value, false); + + // assert + IptcValue actual = profile.GetValues(tag).First(); + Assert.Equal(expectedLength, actual.Value.Length); + } + [Theory] [InlineData(IptcTag.DigitalCreationDate)] [InlineData(IptcTag.ExpirationDate)] @@ -199,13 +216,6 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC ContainsIptcValue(iptcValues, IptcTag.Caption, expectedCaption); } - [Fact] - public void IptcProfile_SetNewValue_RespectsMaxLength() - { - // arrange - var profile = new IptcProfile(); - } - [Theory] [InlineData(IptcTag.ObjectAttribute)] [InlineData(IptcTag.SubjectReference)] @@ -292,7 +302,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC [Fact] public void IptcProfile_RemoveByTag_RemovesAllEntrys() { - // arange + // arrange var profile = new IptcProfile(); profile.SetValue(IptcTag.Byline, "test"); profile.SetValue(IptcTag.Byline, "test2"); @@ -308,7 +318,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC [Fact] public void IptcProfile_RemoveByTagAndValue_Works() { - // arange + // arrange var profile = new IptcProfile(); profile.SetValue(IptcTag.Byline, "test"); profile.SetValue(IptcTag.Byline, "test2"); @@ -322,9 +332,9 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.IPTC } [Fact] - public void IptcProfile_GetValue_RetrievesAllEntrys() + public void IptcProfile_GetValue_RetrievesAllEntries() { - // arange + // arrange var profile = new IptcProfile(); profile.SetValue(IptcTag.Byline, "test"); profile.SetValue(IptcTag.Byline, "test2"); From cbab62dac3a56224f1c7dab2d95bfc28bbfba5a3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 Apr 2020 15:21:14 +0100 Subject: [PATCH 150/213] Capture and throw degenerate matrices. --- .../Exceptions/ImageProcessingException.cs | 13 ++++-- .../Processing/AffineTransformBuilder.cs | 9 +++- .../DegenerateTransformException.cs | 42 +++++++++++++++++++ .../Transforms/TransformUtilities.cs | 29 +++++++++++++ .../Processing/ProjectiveTransformBuilder.cs | 9 +++- .../Transforms/AffineTransformBuilderTests.cs | 7 ++-- .../ProjectiveTransformBuilderTests.cs | 23 ++++++---- .../Transforms/TransformBuilderTestBase.cs | 34 +++++++++------ 8 files changed, 136 insertions(+), 30 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs diff --git a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs index 3c75a6418a..c254eaeb3f 100644 --- a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs +++ b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -8,8 +8,15 @@ namespace SixLabors.ImageSharp /// /// The exception that is thrown when an error occurs when applying a process to an image. /// - public sealed class ImageProcessingException : Exception + public class ImageProcessingException : Exception { + /// + /// Initializes a new instance of the class. + /// + public ImageProcessingException() + { + } + /// /// Initializes a new instance of the class with the name of the /// parameter that causes this exception. @@ -32,4 +39,4 @@ namespace SixLabors.ImageSharp { } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index dde7beb3e9..51a110dfcd 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -284,6 +284,11 @@ namespace SixLabors.ImageSharp.Processing matrix *= factory(size); } + if (TransformUtilities.IsNaN(matrix)) + { + throw new DegenerateTransformException("Matrix is NaN. Check input values."); + } + return matrix; } @@ -299,4 +304,4 @@ namespace SixLabors.ImageSharp.Processing return this; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs b/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs new file mode 100644 index 0000000000..970a044dc6 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs @@ -0,0 +1,42 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Represents an error that occurs during a transform operation. + /// + public sealed class DegenerateTransformException : ImageProcessingException + { + /// + /// Initializes a new instance of the class. + /// + public DegenerateTransformException() + { + } + + /// + /// Initializes a new instance of the class + /// with a specified error message. + /// + /// The message that describes the error. + public DegenerateTransformException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class + /// with a specified error message and a reference to the inner exception that is + /// the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, or a null reference ( in Visual Basic) if no inner exception is specified. + public DegenerateTransformException(string message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs index 0760d2e3e7..329d57f3d0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs @@ -12,6 +12,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal static class TransformUtilities { + /// + /// Returns a value that indicates whether the specified matrix contains any values + /// that are not a number . + /// + /// The transform matrix. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static bool IsNaN(Matrix3x2 matrix) + { + return float.IsNaN(matrix.M11) || float.IsNaN(matrix.M12) + || float.IsNaN(matrix.M21) || float.IsNaN(matrix.M22) + || float.IsNaN(matrix.M31) || float.IsNaN(matrix.M32); + } + + /// + /// Returns a value that indicates whether the specified matrix contains any values + /// that are not a number . + /// + /// The transform matrix. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static bool IsNaN(Matrix4x4 matrix) + { + return float.IsNaN(matrix.M11) || float.IsNaN(matrix.M12) || float.IsNaN(matrix.M13) || float.IsNaN(matrix.M14) + || float.IsNaN(matrix.M21) || float.IsNaN(matrix.M22) || float.IsNaN(matrix.M23) || float.IsNaN(matrix.M24) + || float.IsNaN(matrix.M31) || float.IsNaN(matrix.M32) || float.IsNaN(matrix.M33) || float.IsNaN(matrix.M34) + || float.IsNaN(matrix.M41) || float.IsNaN(matrix.M42) || float.IsNaN(matrix.M43) || float.IsNaN(matrix.M44); + } + /// /// Applies the projective transform against the given coordinates flattened into the 2D space. /// diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index ef44dc16d0..caebc34a36 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -300,6 +300,11 @@ namespace SixLabors.ImageSharp.Processing matrix *= factory(size); } + if (TransformUtilities.IsNaN(matrix)) + { + throw new DegenerateTransformException("Matrix is NaN. Check input values."); + } + return matrix; } @@ -315,4 +320,4 @@ namespace SixLabors.ImageSharp.Processing return this; } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 42017f3afb..70b5be73e5 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; @@ -8,7 +8,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class AffineTransformBuilderTests : TransformBuilderTestBase { - protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); + protected override AffineTransformBuilder CreateBuilder() + => new AffineTransformBuilder(); protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); @@ -67,4 +68,4 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms return Vector2.Transform(sourcePoint, matrix); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 309a73fb4b..22388a0ac1 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -1,6 +1,7 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; using SixLabors.ImageSharp.Processing; @@ -8,20 +9,25 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { public class ProjectiveTransformBuilderTests : TransformBuilderTestBase { - protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(); + protected override ProjectiveTransformBuilder CreateBuilder() + => new ProjectiveTransformBuilder(); - protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) + => builder.AppendRotationDegrees(degrees); - protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) + => builder.AppendRotationDegrees(degrees, origin); - protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) + => builder.AppendRotationRadians(radians); - protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) + => builder.AppendRotationRadians(radians, origin); protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY) - => builder.AppendSkewDegrees(degreesX, degreesY); + => builder.AppendSkewDegrees(degreesX, degreesY); protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY, Vector2 origin) => builder.AppendSkewDegrees(degreesX, degreesY, origin); @@ -44,7 +50,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms protected override void PrependSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) => builder.PrependSkewRadians(radiansX, radiansY, origin); - protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) + => builder.PrependTranslation(translate); protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.PrependRotationRadians(radians, origin); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 21359799e7..8c75cea7fd 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { // These operations should be size-agnostic: var size = new Size(123, 321); - TBuilder builder = this.CreateBuilder(size); + TBuilder builder = this.CreateBuilder(); this.AppendScale(builder, new SizeF(scale)); this.AppendTranslation(builder, translate); @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { // Translate ans scale are size-agnostic: var size = new Size(456, 432); - TBuilder builder = this.CreateBuilder(size); + TBuilder builder = this.CreateBuilder(); this.AppendTranslation(builder, translate); this.AppendScale(builder, new SizeF(scale)); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void LocationOffsetIsPrepended(int locationX, int locationY) { var rectangle = new Rectangle(locationX, locationY, 10, 10); - TBuilder builder = this.CreateBuilder(rectangle); + TBuilder builder = this.CreateBuilder(); this.AppendScale(builder, new SizeF(2, 2)); @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms float y) { var size = new Size(width, height); - TBuilder builder = this.CreateBuilder(size); + TBuilder builder = this.CreateBuilder(); this.AppendRotationDegrees(builder, degrees); @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms float y) { var size = new Size(width, height); - TBuilder builder = this.CreateBuilder(size); + TBuilder builder = this.CreateBuilder(); var centerPoint = new Vector2(cx, cy); this.AppendRotationDegrees(builder, degrees, centerPoint); @@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms float y) { var size = new Size(width, height); - TBuilder builder = this.CreateBuilder(size); + TBuilder builder = this.CreateBuilder(); this.AppendSkewDegrees(builder, degreesX, degreesY); @@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms float y) { var size = new Size(width, height); - TBuilder builder = this.CreateBuilder(size); + TBuilder builder = this.CreateBuilder(); var centerPoint = new Vector2(cx, cy); this.AppendSkewDegrees(builder, degreesX, degreesY, centerPoint); @@ -194,8 +194,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void AppendPrependOpposite() { var rectangle = new Rectangle(-1, -1, 3, 3); - TBuilder b1 = this.CreateBuilder(rectangle); - TBuilder b2 = this.CreateBuilder(rectangle); + TBuilder b1 = this.CreateBuilder(); + TBuilder b2 = this.CreateBuilder(); const float pi = (float)Math.PI; @@ -232,14 +232,24 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.ThrowsAny( () => { - TBuilder builder = this.CreateBuilder(size); + TBuilder builder = this.CreateBuilder(); this.Execute(builder, new Rectangle(Point.Empty, size), Vector2.Zero); }); } - protected TBuilder CreateBuilder(Size size) => this.CreateBuilder(new Rectangle(Point.Empty, size)); + [Fact] + public void ThrowsForInvalidMatrix() + { + Assert.ThrowsAny( + () => + { + TBuilder builder = this.CreateBuilder(); + this.AppendSkewDegrees(builder, 45, 45); + this.Execute(builder, new Rectangle(0, 0, 150, 150), Vector2.Zero); + }); + } - protected abstract TBuilder CreateBuilder(Rectangle rectangle); + protected abstract TBuilder CreateBuilder(); protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); From a8d2d1f8520302a9a622787a7125a826806bf741 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 Apr 2020 15:25:09 +0100 Subject: [PATCH 151/213] Add exception docs. --- src/ImageSharp/Processing/AffineTransformBuilder.cs | 3 +++ src/ImageSharp/Processing/ProjectiveTransformBuilder.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 51a110dfcd..c7007679fc 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -268,6 +268,9 @@ namespace SixLabors.ImageSharp.Processing /// Returns the combined matrix for a given source rectangle. /// /// The rectangle in the source image. + /// + /// The resultant matrix contains one or more values equivalent to . + /// /// The . public Matrix3x2 BuildMatrix(Rectangle sourceRectangle) { diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index caebc34a36..a407074aa2 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -284,6 +284,9 @@ namespace SixLabors.ImageSharp.Processing /// Returns the combined matrix for a given source rectangle. /// /// The rectangle in the source image. + /// + /// The resultant matrix contains one or more values equivalent to . + /// /// The . public Matrix4x4 BuildMatrix(Rectangle sourceRectangle) { From e7f65b940e9e0ca070b2c1d7e4cc5d15fef3798f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 Apr 2020 16:22:01 +0100 Subject: [PATCH 152/213] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 5e48aaa47c..68c5746528 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ SixLabors.ImageSharp [![License: AGPL v3](https://img.shields.io/badge/license-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ImageSharp/General?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=flat&logo=twitter)](https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&url=https%3a%2f%2fgithub.com%2fSixLabors%2fImageSharp&via=sixlabors) -[![OpenCollective](https://opencollective.com/imagesharp/backers/badge.svg)](#backers) -[![OpenCollective](https://opencollective.com/imagesharp/sponsors/badge.svg)](#sponsors) From 562b3b9f4a905e3d19a4a502f878b51e818882a3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 Apr 2020 22:57:56 +0100 Subject: [PATCH 153/213] Check determinant and update error message. --- src/ImageSharp/Processing/AffineTransformBuilder.cs | 4 ++-- src/ImageSharp/Processing/ProjectiveTransformBuilder.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index c7007679fc..d793c67a2b 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -287,9 +287,9 @@ namespace SixLabors.ImageSharp.Processing matrix *= factory(size); } - if (TransformUtilities.IsNaN(matrix)) + if (TransformUtilities.IsNaN(matrix) || matrix.GetDeterminant() == 0) { - throw new DegenerateTransformException("Matrix is NaN. Check input values."); + throw new DegenerateTransformException("Matrix is degenerate. Check input values."); } return matrix; diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index a407074aa2..0535eaeb1c 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -303,9 +303,9 @@ namespace SixLabors.ImageSharp.Processing matrix *= factory(size); } - if (TransformUtilities.IsNaN(matrix)) + if (TransformUtilities.IsNaN(matrix) || matrix.GetDeterminant() == 0) { - throw new DegenerateTransformException("Matrix is NaN. Check input values."); + throw new DegenerateTransformException("Matrix is degenerate. Check input values."); } return matrix; From ff28048fa397cfb192c4aad2c168e7f776f0c657 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 Apr 2020 23:55:26 +0100 Subject: [PATCH 154/213] Remove inheritance --- src/ImageSharp/Common/Exceptions/ImageProcessingException.cs | 2 +- .../Processors/Transforms/DegenerateTransformException.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs index c254eaeb3f..ccd0b71e54 100644 --- a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs +++ b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp /// /// The exception that is thrown when an error occurs when applying a process to an image. /// - public class ImageProcessingException : Exception + public sealed class ImageProcessingException : Exception { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs b/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs index 970a044dc6..4d46540bcc 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Represents an error that occurs during a transform operation. /// - public sealed class DegenerateTransformException : ImageProcessingException + public sealed class DegenerateTransformException : Exception { /// /// Initializes a new instance of the class. From f21af373213efc6263fb5eb2301eae1384411e20 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 22 Apr 2020 23:56:26 +0100 Subject: [PATCH 155/213] Add determinant check and update check location/message --- .../Processing/AffineTransformBuilder.cs | 37 ++++++++++++++--- .../Transforms/TransformUtilities.cs | 22 ++++++++++ .../Processing/ProjectiveTransformBuilder.cs | 41 +++++++++++++++---- 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index d793c67a2b..1478d2951b 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -247,15 +247,33 @@ namespace SixLabors.ImageSharp.Processing /// Prepends a raw matrix. /// /// The matrix to prepend. + /// + /// The resultant matrix is degenerate containing one or more values equivalent + /// to or a zero determinant and therefore cannot be used + /// for linear transforms. + /// /// The . - public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) => this.Prepend(_ => matrix); + public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) + { + CheckDegenerate(matrix); + return this.Prepend(_ => matrix); + } /// /// Appends a raw matrix. /// /// The matrix to append. + /// + /// The resultant matrix is degenerate containing one or more values equivalent + /// to or a zero determinant and therefore cannot be used + /// for linear transforms. + /// /// The . - public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) => this.Append(_ => matrix); + public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) + { + CheckDegenerate(matrix); + return this.Append(_ => matrix); + } /// /// Returns the combined matrix for a given source size. @@ -269,7 +287,9 @@ namespace SixLabors.ImageSharp.Processing /// /// The rectangle in the source image. /// - /// The resultant matrix contains one or more values equivalent to . + /// The resultant matrix is degenerate containing one or more values equivalent + /// to or a zero determinant and therefore cannot be used + /// for linear transforms. /// /// The . public Matrix3x2 BuildMatrix(Rectangle sourceRectangle) @@ -287,12 +307,17 @@ namespace SixLabors.ImageSharp.Processing matrix *= factory(size); } - if (TransformUtilities.IsNaN(matrix) || matrix.GetDeterminant() == 0) + CheckDegenerate(matrix); + + return matrix; + } + + private static void CheckDegenerate(Matrix3x2 matrix) + { + if (TransformUtilities.IsDegenerate(matrix)) { throw new DegenerateTransformException("Matrix is degenerate. Check input values."); } - - return matrix; } private AffineTransformBuilder Prepend(Func factory) diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs index 329d57f3d0..b474b43712 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs @@ -12,6 +12,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// internal static class TransformUtilities { + /// + /// Returns a value that indicates whether the specified matrix is degenerate + /// containing one or more values equivalent to or a + /// zero determinant and therefore cannot be used for linear transforms. + /// + /// The transform matrix. + public static bool IsDegenerate(Matrix3x2 matrix) + => IsNaN(matrix) || IsZero(matrix.GetDeterminant()); + + /// + /// Returns a value that indicates whether the specified matrix is degenerate + /// containing one or more values equivalent to or a + /// zero determinant and therefore cannot be used for linear transforms. + /// + /// The transform matrix. + public static bool IsDegenerate(Matrix4x4 matrix) + => IsNaN(matrix) || IsZero(matrix.GetDeterminant()); + + [MethodImpl(InliningOptions.ShortMethod)] + private static bool IsZero(float a) + => a > -Constants.EpsilonSquared && a < Constants.EpsilonSquared; + /// /// Returns a value that indicates whether the specified matrix contains any values /// that are not a number . diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index 0535eaeb1c..b7e65b4cc0 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Numerics; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Processing.Processors.Transforms; namespace SixLabors.ImageSharp.Processing @@ -263,29 +264,50 @@ namespace SixLabors.ImageSharp.Processing /// Prepends a raw matrix. /// /// The matrix to prepend. + /// + /// The resultant matrix is degenerate containing one or more values equivalent + /// to or a zero determinant and therefore cannot be used + /// for linear transforms. + /// /// The . - public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) => this.Prepend(_ => matrix); + public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) + { + CheckDegenerate(matrix); + return this.Prepend(_ => matrix); + } /// /// Appends a raw matrix. /// /// The matrix to append. + /// + /// The resultant matrix is degenerate containing one or more values equivalent + /// to or a zero determinant and therefore cannot be used + /// for linear transforms. + /// /// The . - public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) => this.Append(_ => matrix); + public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) + { + CheckDegenerate(matrix); + return this.Append(_ => matrix); + } /// /// Returns the combined matrix for a given source size. /// /// The source image size. /// The . - public Matrix4x4 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); + public Matrix4x4 BuildMatrix(Size sourceSize) + => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); /// /// Returns the combined matrix for a given source rectangle. /// /// The rectangle in the source image. /// - /// The resultant matrix contains one or more values equivalent to . + /// The resultant matrix is degenerate containing one or more values equivalent + /// to or a zero determinant and therefore cannot be used + /// for linear transforms. /// /// The . public Matrix4x4 BuildMatrix(Rectangle sourceRectangle) @@ -303,12 +325,17 @@ namespace SixLabors.ImageSharp.Processing matrix *= factory(size); } - if (TransformUtilities.IsNaN(matrix) || matrix.GetDeterminant() == 0) + CheckDegenerate(matrix); + + return matrix; + } + + private static void CheckDegenerate(Matrix4x4 matrix) + { + if (TransformUtilities.IsDegenerate(matrix)) { throw new DegenerateTransformException("Matrix is degenerate. Check input values."); } - - return matrix; } private ProjectiveTransformBuilder Prepend(Func factory) From 5415bde174f41e5a6b3fcf039af22a3897911a26 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 23 Apr 2020 10:01:33 +0200 Subject: [PATCH 156/213] Throw exception when malformed apple png chunk is detected (#410) --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 272f93d108..757b084816 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -9,7 +9,7 @@ using System.IO.Compression; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using SixLabors.ImageSharp.Advanced; + using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; @@ -215,6 +215,9 @@ namespace SixLabors.ImageSharp.Formats.Png case PngChunkType.End: this.isEndChunkReached = true; break; + case PngChunkType.MalformedApple: + PngThrowHelper.ThrowInvalidChunkType("Malformed Apple PNG detected! This PNG file is not conform to the specification and cannot be decoded."); + break; } } finally @@ -1039,7 +1042,7 @@ namespace SixLabors.ImageSharp.Formats.Png var uncompressedBytes = new List(); - // Note: this uses the a buffer which is only 4 bytes long to read the stream, maybe allocating a larger buffer makes sense here. + // Note: this uses a buffer which is only 4 bytes long to read the stream, maybe allocating a larger buffer makes sense here. int bytesRead = inflateStream.CompressedStream.Read(this.buffer, 0, this.buffer.Length); while (bytesRead != 0) { From b394e0594e4ad50fe8835e7d46fbc4fa9cc4acd2 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 23 Apr 2020 13:05:52 +0200 Subject: [PATCH 157/213] Add additional chunk types --- src/ImageSharp/Formats/Png/PngChunkType.cs | 54 ++++++++++++++++++- .../Formats/Png/PngChunkTypeTests.cs | 27 +++++++--- 2 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs index e41b49066a..67e5ccf557 100644 --- a/src/ImageSharp/Formats/Png/PngChunkType.cs +++ b/src/ImageSharp/Formats/Png/PngChunkType.cs @@ -73,6 +73,58 @@ namespace SixLabors.ImageSharp.Formats.Png /// either alpha values associated with palette entries (for indexed-color images) /// or a single transparent color (for grayscale and true color images). /// - Transparency = 0x74524E53U + Transparency = 0x74524E53U, + + /// + /// The tIME chunk gives the time of the last image modification (not the time of initial image creation). + /// + Time = 0x74494d45, + + /// + /// The bKGD chunk specifies a default background colour to present the image against. + /// If there is any other preferred background, either user-specified or part of a larger page (as in a browser), + /// the bKGD chunk should be ignored. + /// + Background = 0x624b4744, + + /// + /// The iCCP chunk contains a embedded color profile. If the iCCP chunk is present, + /// the image samples conform to the colour space represented by the embedded ICC profile as defined by the International Color Consortium. + /// + EmbeddedColorProfile = 0x69434350, + + /// + /// The sBIT chunk defines the original number of significant bits (which can be less than or equal to the sample depth). + /// This allows PNG decoders to recover the original data losslessly even if the data had a sample depth not directly supported by PNG. + /// + SignificantBits = 0x73424954, + + /// + /// If the sRGB chunk is present, the image samples conform to the sRGB colour space [IEC 61966-2-1] and should be displayed + /// using the specified rendering intent defined by the International Color Consortium. + /// + StandardRgbColourSpace = 0x73524742, + + /// + /// The hIST chunk gives the approximate usage frequency of each colour in the palette. + /// + Histogram = 0x68495354, + + /// + /// The sPLT chunk contains the suggested palette. + /// + SuggestedPalette = 0x73504c54, + + /// + /// The cHRM chunk may be used to specify the 1931 CIE x,y chromaticities of the red, + /// green, and blue display primaries used in the image, and the referenced white point. + /// + Chroma = 0x6348524d, + + /// + /// Malformed chunk named CgBI produced by apple, which is not conform to the specification. + /// Related issue is here https://github.com/SixLabors/ImageSharp/issues/410 + /// + MalformedApple = 0x43674249 } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs index 2e8c0de272..f3984ac823 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs @@ -13,15 +13,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [Fact] public void ChunkTypeIdsAreCorrect() { - Assert.Equal(PngChunkType.Header, GetType("IHDR")); - Assert.Equal(PngChunkType.Palette, GetType("PLTE")); - Assert.Equal(PngChunkType.Data, GetType("IDAT")); - Assert.Equal(PngChunkType.End, GetType("IEND")); + Assert.Equal(PngChunkType.Header, GetType("IHDR")); + Assert.Equal(PngChunkType.Palette, GetType("PLTE")); + Assert.Equal(PngChunkType.Data, GetType("IDAT")); + Assert.Equal(PngChunkType.End, GetType("IEND")); Assert.Equal(PngChunkType.Transparency, GetType("tRNS")); - Assert.Equal(PngChunkType.Text, GetType("tEXt")); - Assert.Equal(PngChunkType.Gamma, GetType("gAMA")); - Assert.Equal(PngChunkType.Physical, GetType("pHYs")); - Assert.Equal(PngChunkType.Exif, GetType("eXIf")); + Assert.Equal(PngChunkType.Text, GetType("tEXt")); + Assert.Equal(PngChunkType.InternationalText, GetType("iTXt")); + Assert.Equal(PngChunkType.CompressedText, GetType("zTXt")); + Assert.Equal(PngChunkType.Chroma, GetType("cHRM")); + Assert.Equal(PngChunkType.Gamma, GetType("gAMA")); + Assert.Equal(PngChunkType.Physical, GetType("pHYs")); + Assert.Equal(PngChunkType.Exif, GetType("eXIf")); + Assert.Equal(PngChunkType.Time, GetType("tIME")); + Assert.Equal(PngChunkType.Background, GetType("bKGD")); + Assert.Equal(PngChunkType.EmbeddedColorProfile, GetType("iCCP")); + Assert.Equal(PngChunkType.StandardRgbColourSpace, GetType("sRGB")); + Assert.Equal(PngChunkType.SignificantBits, GetType("sBIT")); + Assert.Equal(PngChunkType.Histogram, GetType("hIST")); + Assert.Equal(PngChunkType.SuggestedPalette, GetType("sPLT")); + Assert.Equal(PngChunkType.MalformedApple, GetType("CgBI")); } private static PngChunkType GetType(string text) From da35e847feb422f34d72948fa1d5498460cd5a00 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 23 Apr 2020 13:55:15 +0200 Subject: [PATCH 158/213] Add tests for jpg encoder preserving metadata --- .../Formats/Jpg/JpegEncoderTests.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index bb79abf54d..6cbdb83fcd 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -1,10 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Collections.Generic; using System.IO; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; +using SixLabors.ImageSharp.Metadata.Profiles.Icc; +using SixLabors.ImageSharp.Metadata.Profiles.Iptc; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -215,5 +219,70 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } } + + [Fact] + public void Encode_PreservesIptcProfile() + { + // arrange + using var input = new Image(1, 1); + input.Metadata.IptcProfile = new IptcProfile(); + input.Metadata.IptcProfile.SetValue(IptcTag.Byline, "unit_test"); + var encoder = new JpegEncoder(); + + // act + using var memStream = new MemoryStream(); + input.Save(memStream, encoder); + + // assert + memStream.Position = 0; + using var output = Image.Load(memStream); + IptcProfile actual = output.Metadata.IptcProfile; + Assert.NotNull(actual); + IEnumerable values = input.Metadata.IptcProfile.Values; + Assert.Equal(values, actual.Values); + } + + [Fact] + public void Encode_PreservesExifProfile() + { + // arrange + using var input = new Image(1, 1); + input.Metadata.ExifProfile = new ExifProfile(); + input.Metadata.ExifProfile.SetValue(ExifTag.Software, "unit_test"); + var encoder = new JpegEncoder(); + + // act + using var memStream = new MemoryStream(); + input.Save(memStream, encoder); + + // assert + memStream.Position = 0; + using var output = Image.Load(memStream); + ExifProfile actual = output.Metadata.ExifProfile; + Assert.NotNull(actual); + IReadOnlyList values = input.Metadata.ExifProfile.Values; + Assert.Equal(values, actual.Values); + } + + [Fact] + public void Encode_PreservesIccProfile() + { + // arrange + using var input = new Image(1, 1); + input.Metadata.IccProfile = new IccProfile(IccTestDataProfiles.Profile_Random_Array); + var encoder = new JpegEncoder(); + + // act + using var memStream = new MemoryStream(); + input.Save(memStream, encoder); + + // assert + memStream.Position = 0; + using var output = Image.Load(memStream); + IccProfile actual = output.Metadata.IccProfile; + Assert.NotNull(actual); + IccProfile values = input.Metadata.IccProfile; + Assert.Equal(values.Entries, actual.Entries); + } } } From 67c4007d3d61207ca787a3f226c18f17a33d502a Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 23 Apr 2020 15:55:32 +0200 Subject: [PATCH 159/213] Additional png test cases --- src/ImageSharp/Formats/Png/PngThrowHelper.cs | 5 +- .../Formats/Png/PngDecoderTests.Chunks.cs | 15 ++ .../Formats/Png/PngDecoderTests.cs | 239 +++++++++++++----- tests/ImageSharp.Tests/TestImages.cs | 31 ++- tests/Images/Input/Png/basn3p01.png | Bin 0 -> 112 bytes tests/Images/Input/Png/basn3p02.png | Bin 0 -> 146 bytes tests/Images/Input/Png/basn3p04.png | Bin 0 -> 216 bytes tests/Images/Input/Png/basn3p08.png | Bin 0 -> 1286 bytes tests/Images/Input/Png/issues/Issue_410.png | Bin 0 -> 674 bytes tests/Images/Input/Png/xc1n0g08.png | Bin 0 -> 138 bytes tests/Images/Input/Png/xc9n2c08.png | Bin 0 -> 145 bytes tests/Images/Input/Png/xd0n2c08.png | Bin 0 -> 145 bytes tests/Images/Input/Png/xd3n2c08.png | Bin 0 -> 145 bytes tests/Images/Input/Png/xdtn0g01.png | Bin 0 -> 61 bytes 14 files changed, 220 insertions(+), 70 deletions(-) create mode 100644 tests/Images/Input/Png/basn3p01.png create mode 100644 tests/Images/Input/Png/basn3p02.png create mode 100644 tests/Images/Input/Png/basn3p04.png create mode 100644 tests/Images/Input/Png/basn3p08.png create mode 100644 tests/Images/Input/Png/issues/Issue_410.png create mode 100644 tests/Images/Input/Png/xc1n0g08.png create mode 100644 tests/Images/Input/Png/xc9n2c08.png create mode 100644 tests/Images/Input/Png/xd0n2c08.png create mode 100644 tests/Images/Input/Png/xd3n2c08.png create mode 100644 tests/Images/Input/Png/xdtn0g01.png diff --git a/src/ImageSharp/Formats/Png/PngThrowHelper.cs b/src/ImageSharp/Formats/Png/PngThrowHelper.cs index dcb643d036..b0a2571eae 100644 --- a/src/ImageSharp/Formats/Png/PngThrowHelper.cs +++ b/src/ImageSharp/Formats/Png/PngThrowHelper.cs @@ -20,11 +20,14 @@ namespace SixLabors.ImageSharp.Formats.Png [MethodImpl(InliningOptions.ColdPath)] public static void ThrowInvalidChunkType() => throw new InvalidImageContentException("Invalid PNG data."); + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowInvalidChunkType(string message) => throw new InvalidImageContentException(message); + [MethodImpl(InliningOptions.ColdPath)] public static void ThrowInvalidChunkCrc(string chunkTypeName) => throw new InvalidImageContentException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!"); [MethodImpl(InliningOptions.ColdPath)] - public static void ThrowNotSupportedColor() => new NotSupportedException("Unsupported PNG color type"); + public static void ThrowNotSupportedColor() => throw new NotSupportedException("Unsupported PNG color type"); [MethodImpl(InliningOptions.ColdPath)] public static void ThrowUnknownFilter() => throw new InvalidImageContentException("Unknown filter type."); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index 297512fa6a..6cefff95d4 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -6,6 +6,7 @@ using System.IO; using System.Text; using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -78,6 +79,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Fact] + public void CalculateCrc_Works() + { + // arrange + var data = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; + var crc = new Crc32(); + + // act + crc.Update(data); + + // assert + Assert.Equal(0x88AA689F, crc.Value); + } + private static string GetChunkTypeName(uint value) { var data = new byte[4]; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index b08025f532..c4b5d0b4bf 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -4,7 +4,6 @@ using System.IO; using Microsoft.DotNet.RemoteExecutor; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -26,62 +25,21 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png public static readonly string[] CommonTestImages = { TestImages.Png.Splash, - TestImages.Png.Indexed, TestImages.Png.FilterVar, - TestImages.Png.Bad.ChunkLength1, - TestImages.Png.Bad.CorruptedChunk, TestImages.Png.VimImage1, + TestImages.Png.VimImage2, TestImages.Png.VersioningImage1, TestImages.Png.VersioningImage2, TestImages.Png.SnakeGame, - TestImages.Png.Banner7Adam7InterlaceMode, - TestImages.Png.Banner8Index, - - TestImages.Png.Bad.ChunkLength2, - TestImages.Png.VimImage2, TestImages.Png.Rgb24BppTrans, - TestImages.Png.GrayA8Bit, - TestImages.Png.Gray1BitTrans, - TestImages.Png.Bad.ZlibOverflow, - TestImages.Png.Bad.ZlibOverflow2, - TestImages.Png.Bad.ZlibZtxtBadHeader, - TestImages.Png.Bad.Issue1047_BadEndChunk - }; - - public static readonly string[] TestImages48Bpp = - { - TestImages.Png.Rgb48Bpp, - TestImages.Png.Rgb48BppInterlaced - }; - - public static readonly string[] TestImages64Bpp = - { - TestImages.Png.Rgba64Bpp, - TestImages.Png.Rgb48BppTrans - }; - - public static readonly string[] TestImagesL16Bit = - { - TestImages.Png.L16Bit, - }; - public static readonly string[] TestImagesGrayAlpha16Bit = - { - TestImages.Png.GrayAlpha16Bit, - TestImages.Png.GrayTrns16BitInterlaced + TestImages.Png.Bad.ChunkLength1, + TestImages.Png.Bad.ChunkLength2, }; - public static readonly string[] TestImagesL8BitInterlaced = - { - TestImages.Png.GrayAlpha1BitInterlaced, - TestImages.Png.GrayAlpha2BitInterlaced, - TestImages.Png.Gray4BitInterlaced, - TestImages.Png.GrayA8BitInterlaced - }; - public static readonly string[] TestImagesIssue1014 = { TestImages.Png.Issue1014_1, TestImages.Png.Issue1014_2, @@ -95,6 +53,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png TestImages.Png.Issue1177_2 }; + public static readonly string[] CorruptedTestImages = + { + TestImages.Png.Bad.CorruptedChunk, + TestImages.Png.Bad.ZlibOverflow, + TestImages.Png.Bad.ZlibOverflow2, + TestImages.Png.Bad.ZlibZtxtBadHeader, + }; + [Theory] [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] public void Decode(TestImageProvider provider) @@ -103,25 +69,28 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png using (Image image = provider.GetImage(PngDecoder)) { image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); + } + } - // We don't have another x-plat reference decoder that can be compared for this image. - if (provider.Utility.SourceFileOrDescription == TestImages.Png.Bad.Issue1047_BadEndChunk) - { - if (TestEnvironment.IsWindows) - { - image.CompareToOriginal(provider, ImageComparer.Exact, (IImageDecoder)SystemDrawingReferenceDecoder.Instance); - } - } - else - { - image.CompareToOriginal(provider, ImageComparer.Exact); - } + [Theory] + [WithFile(TestImages.Png.GrayA8Bit, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.Gray1BitTrans, PixelTypes.Rgba32)] + public void Decode_GrayWithAlpha(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); } } [Theory] [WithFile(TestImages.Png.Interlaced, PixelTypes.Rgba32)] - public void Decode_Interlaced_ImageIsCorrect(TestImageProvider provider) + [WithFile(TestImages.Png.Banner7Adam7InterlaceMode, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.Banner8Index, PixelTypes.Rgba32)] + public void Decode_Interlaced(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(PngDecoder)) @@ -132,7 +101,25 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } [Theory] - [WithFileCollection(nameof(TestImages48Bpp), PixelTypes.Rgb48)] + [WithFile(TestImages.Png.Indexed, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.Banner8Index, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.PalettedTwoColor, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.PalettedFourColor, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.PalettedSixteenColor, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.Paletted256Colors, PixelTypes.Rgba32)] + public void Decode_Indexed(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); + } + } + + [Theory] + [WithFile(TestImages.Png.Rgb48Bpp, PixelTypes.Rgb48)] + [WithFile(TestImages.Png.Rgb48BppInterlaced, PixelTypes.Rgb48)] public void Decode_48Bpp(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -144,7 +131,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } [Theory] - [WithFileCollection(nameof(TestImages64Bpp), PixelTypes.Rgba64)] + [WithFile(TestImages.Png.Rgba64Bpp, PixelTypes.Rgba64)] + [WithFile(TestImages.Png.Rgb48BppTrans, PixelTypes.Rgba64)] public void Decode_64Bpp(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -156,7 +144,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } [Theory] - [WithFileCollection(nameof(TestImagesL8BitInterlaced), PixelTypes.Rgba32)] + [WithFile(TestImages.Png.GrayAlpha1BitInterlaced, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.GrayAlpha2BitInterlaced, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.Gray4BitInterlaced, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.GrayA8BitInterlaced, PixelTypes.Rgba32)] public void Decoder_L8bitInterlaced(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -168,7 +159,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } [Theory] - [WithFileCollection(nameof(TestImagesL16Bit), PixelTypes.Rgb48)] + [WithFile(TestImages.Png.L16Bit, PixelTypes.Rgb48)] public void Decode_L16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -180,7 +171,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } [Theory] - [WithFileCollection(nameof(TestImagesGrayAlpha16Bit), PixelTypes.Rgba64)] + [WithFile(TestImages.Png.GrayAlpha16Bit, PixelTypes.Rgba64)] + [WithFile(TestImages.Png.GrayTrns16BitInterlaced, PixelTypes.Rgba64)] public void Decode_GrayAlpha16Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -193,7 +185,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [Theory] [WithFile(TestImages.Png.GrayA8BitInterlaced, PixelTypes)] - public void Decoder_CanDecodeGrey8bitWithAlpha(TestImageProvider provider) + public void Decoder_CanDecode_Grey8bitInterlaced_WithAlpha(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + image.CompareToOriginal(provider, ImageComparer.Exact); + } + } + + [Theory] + [WithFileCollection(nameof(CorruptedTestImages), PixelTypes.Rgba32)] + public void Decoder_CanDecode_CorruptedImages(TestImageProvider provider) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage(PngDecoder)) @@ -232,9 +236,63 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [WithFile(TestImages.Png.Bad.MissingDataChunk, PixelTypes.Rgba32)] + public void Decode_MissingDataChunk_ThrowsException(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + System.Exception ex = Record.Exception( + () => + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + } + }); + Assert.NotNull(ex); + Assert.Contains("PNG Image does not contain a data chunk", ex.Message); + } + + [Theory] + [WithFile(TestImages.Png.Bad.BitDepthZero, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.Bad.BitDepthThree, PixelTypes.Rgba32)] + public void Decode_InvalidBitDepth_ThrowsException(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + System.Exception ex = Record.Exception( + () => + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + } + }); + Assert.NotNull(ex); + Assert.Contains("Invalid or unsupported bit depth", ex.Message); + } + + [Theory] + [WithFile(TestImages.Png.Bad.ColorTypeOne, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.Bad.ColorTypeNine, PixelTypes.Rgba32)] + public void Decode_InvalidColorType_ThrowsException(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + System.Exception ex = Record.Exception( + () => + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + } + }); + Assert.NotNull(ex); + Assert.Contains("Invalid or unsupported color type", ex.Message); + } + + // https://github.com/SixLabors/ImageSharp/issues/1014 [Theory] [WithFileCollection(nameof(TestImagesIssue1014), PixelTypes.Rgba32)] - public void Issue1014(TestImageProvider provider) + public void Issue1014_DataSplitOverMultipleIDatChunks(TestImageProvider provider) where TPixel : unmanaged, IPixel { System.Exception ex = Record.Exception( @@ -249,9 +307,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Null(ex); } + // https://github.com/SixLabors/ImageSharp/issues/1177 [Theory] [WithFileCollection(nameof(TestImagesIssue1177), PixelTypes.Rgba32)] - public void Issue1177(TestImageProvider provider) + public void Issue1177_CRC_Omitted(TestImageProvider provider) where TPixel : unmanaged, IPixel { System.Exception ex = Record.Exception( @@ -266,6 +325,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Null(ex); } + // https://github.com/SixLabors/ImageSharp/issues/1127 [Theory] [WithFile(TestImages.Png.Issue1127, PixelTypes.Rgba32)] public void Issue1127(TestImageProvider provider) @@ -283,6 +343,53 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Null(ex); } + // https://github.com/SixLabors/ImageSharp/issues/1047 + [Theory] + [WithFile(TestImages.Png.Bad.Issue1047_BadEndChunk, PixelTypes.Rgba32)] + public void Issue1047(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + System.Exception ex = Record.Exception( + () => + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + + // We don't have another x-plat reference decoder that can be compared for this image. + if (TestEnvironment.IsWindows) + { + image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); + } + } + }); + Assert.Null(ex); + } + + // https://github.com/SixLabors/ImageSharp/issues/410 + [Theory] + [WithFile(TestImages.Png.Bad.Issue410_MalformedApplePng, PixelTypes.Rgba32)] + public void Issue410_MalformedApplePng(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + System.Exception ex = Record.Exception( + () => + { + using (Image image = provider.GetImage(PngDecoder)) + { + image.DebugSave(provider); + + // We don't have another x-plat reference decoder that can be compared for this image. + if (TestEnvironment.IsWindows) + { + image.CompareToOriginal(provider, ImageComparer.Exact, SystemDrawingReferenceDecoder.Instance); + } + } + }); + Assert.NotNull(ex); + Assert.Contains("Malformed Apple PNG detected!", ex.Message); + } + [Theory] [WithFile(TestImages.Png.Splash, PixelTypes.Rgba32)] [WithFile(TestImages.Png.Bike, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 18fd84331f..bec0c66242 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -65,6 +65,12 @@ namespace SixLabors.ImageSharp.Tests public const string Filter3 = "Png/filter3.png"; public const string Filter4 = "Png/filter4.png"; + // Paletted images also from http://www.schaik.com/pngsuite/pngsuite_fil_png.html + public const string PalettedTwoColor = "Png/basn3p01.png"; + public const string PalettedFourColor = "Png/basn3p02.png"; + public const string PalettedSixteenColor = "Png/basn3p04.png"; + public const string Paletted256Colors = "Png/basn3p08.png"; + // Filter changing per scanline public const string FilterVar = "Png/filterVar.png"; @@ -93,6 +99,8 @@ namespace SixLabors.ImageSharp.Tests public const string Issue1014_4 = "Png/issues/Issue_1014_4.png"; public const string Issue1014_5 = "Png/issues/Issue_1014_5.png"; public const string Issue1014_6 = "Png/issues/Issue_1014_6.png"; + + // Issue 1127: https://github.com/SixLabors/ImageSharp/issues/1127 public const string Issue1127 = "Png/issues/Issue_1127.png"; // Issue 1177: https://github.com/SixLabors/ImageSharp/issues/1177 @@ -101,14 +109,31 @@ namespace SixLabors.ImageSharp.Tests public static class Bad { - // Odd chunk lengths - public const string ChunkLength1 = "Png/chunklength1.png"; - public const string ChunkLength2 = "Png/chunklength2.png"; + public const string MissingDataChunk = "Png/xdtn0g01.png"; public const string CorruptedChunk = "Png/big-corrupted-chunk.png"; + + // Zlib errors. public const string ZlibOverflow = "Png/zlib-overflow.png"; public const string ZlibOverflow2 = "Png/zlib-overflow2.png"; public const string ZlibZtxtBadHeader = "Png/zlib-ztxt-bad-header.png"; + + // Odd chunk lengths + public const string ChunkLength1 = "Png/chunklength1.png"; + public const string ChunkLength2 = "Png/chunklength2.png"; + + // Issue 1047: https://github.com/SixLabors/ImageSharp/issues/1047 public const string Issue1047_BadEndChunk = "Png/issues/Issue_1047.png"; + + // Issue 410: https://github.com/SixLabors/ImageSharp/issues/410 + public const string Issue410_MalformedApplePng = "Png/issues/Issue_410.png"; + + // Bad bit depth. + public const string BitDepthZero = "Png/xd0n2c08.png"; + public const string BitDepthThree = "Png/xd3n2c08.png"; + + // Invalid color type. + public const string ColorTypeOne = "Png/xc1n0g08.png"; + public const string ColorTypeNine = "Png/xc9n2c08.png"; } public static readonly string[] All = diff --git a/tests/Images/Input/Png/basn3p01.png b/tests/Images/Input/Png/basn3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..b145c2b8eff1f4298e540bfae5c1351d015a3592 GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnL3?x0byx0z;SkfJR9T^zg78t&m77ygJ1^9%x zzWcAFl=eSI>XI5zMAXy8F{ENn@&k4zHj_up0tD0@h%3W?AY}Lt#0>va?X`CSX(dk=$B>FS$v@Vz>816FsF9(VN75txh7sS~8e>Vez z3y|e3}y1F=z>r=LEEca@LnZf*~BA0ROZ5~$d#4)lIa>n+tGAx#s~NCh;!h=Q?&7t5~~Lk>mL*|1x+L`Ivp6mn?kJ^kK$c6a~%|NrOteLPR)ru^*4 zh?oc>ipx)wHw!xP<||VqG2mh2yNQ1IZKr30Xr(I7PBXU z(o_;ftk^?X5O*qmM)+A^aUR*s!>r3PlcI=3mc_D63M-aHQVj83+hHDKi)~wG8A%eb zMRFVzAa0kL4aW(lxy(-(A3@r7{KRdCcI^9^ zBwSWlMY4uMp(p@%T`0C7K$rnonuoRmLY9xP#5bTx(RKJi zCYfG^*s^*-{Ro^e4Kgw{Dlmv)JpjQ5bKwF@CLI|%59=nhA>e#HJh5GNjRLr(&Jco- zL=roU($L^w70~)&xPh+uFV&-K!K0w3W-9Hy@g@HWXL3ML4|%5ULen8 zlT@|D2@;VI*iada4446_ptp_#Sul*Cx7Y6>PlSiq8TyN-q=y}cXZX&@20)p=ihIP{CfA$Z*4W@ zEr$zzJ<~t_(0G1&!T9U{_Iz>DPFy@Dgq4(i*+1}U*ZiG1m)32#<4sRFJ5!AP>yZ}L zzdq~5lB&|C6*=qgy?nj!is#SN$*Gwo6M?qJgKJtd1_tvb_xS3qJuRh&eH)f1f0J@< z)4uq(Z_li{H~+s=+3L-xjU7X)ZvEUC-CLA+t^7d7$jI)tsK~;c&XdnBOC5Txp}1)@ zusm-vWl2G`{dnN}K>pDE=;yi{rVB@Y3B-HrtGOePxNz#}j}FD`z3|nlwikX+ZZ56= zAY&lKTUG9w&2^VN89D}o5=^>%~&6ID5>`0fk%7K&zZcY&F#znJTW|E zB5&cFwM~ly35&;HdZq5*>W9rM<&V4Wr%mNt{B`@CxYpR8I;^7!?Tc=wu6t&Du2Ec< zKIiz-xXN3dttqGahAW20Qo6MzgSk7e_{!(?CKyw`*?j|NY=7wG%F`JaWZ(VOm8CUr z$$no_)1uMK%W6)nN!IrL6EB>puUj#i+1xg}<&qUPnY6#j4&NW^MpZNn{t+Cq+^l@L JEAySt{s-!kV`~5a literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/issues/Issue_410.png b/tests/Images/Input/Png/issues/Issue_410.png new file mode 100644 index 0000000000000000000000000000000000000000..ad3581fbba7ea9d157f10d0e68938cef35ef7465 GIT binary patch literal 674 zcmV;T0$u%yP)e@KzIrsU^ciGghC4n zI=}*>iC;y+$1TWuT&}r)NtW4}otfXx0&wKIt{X*Bl%{F=d_JGA50s{98bwj$x~>az zOV@RsQc7Pl3lUM*b$u2m4Z|?XvMgUeq^hba(=^R*pJY{4)$4~^lSM@A8>N&| zLI}|`O%t`JX_`g|A-po8l+ur!bR5U&8}mHRo2%}9-}n3Wce~wA*iaAzK|f+ik|Yru zT}nJ2k4I}O%d%{_TrQI&NxFLkK@b1{6h%?=DY4)0_uNhLJkPsE48t(yq{QKHI9Qft zb-(3#o&x~HaUAphp_I}uwcIpK(_JLXvOJX%QyP#l#$;KRyWg6oX#fDiFbu~i@!z4{ zZnvALqau`GjIq^fwGwso3nea>%SANxL)}aWA)C!+(_cT7`YDt^LM#=@zLP?sdH}!=ReJ?f8vJKaR2}S07*qo IM6N<$g7DNg_y7O^ literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/xc1n0g08.png b/tests/Images/Input/Png/xc1n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..940422737011509e21d5c02e879c643a83d360e6 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE2qfRFb@ByLEa{HEjtq=#3k+XOiwE)@JzX3_ zD&{1oB&aZmaGco8!^+yj&!PF_yS#lurGboy!70HB=_!jUV|dtDd-^||`uG3*kM?JU ih7v%T2UAm1SQrAH{wp+nbR!aI7=x#)pUXO@geCxzGb>{N literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/xc9n2c08.png b/tests/Images/Input/Png/xc9n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..b11c2a7b4049475d967a8cc76b93ef1039684a3a GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE2_&^8vlam5jgR42*3H3|~x(2l72UT^vIy z=DfXnkdwiHhsmM!&BVXki-fIRw7)F;aqgk^7G4(X1}>2wG7H{5sr9LFXk_B|YL`FM q!Y-omVL^$7@=Axs-38@~4=^@u{29mZaNZkeCWEJ|pUXO@geCyFeJ}z5 literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Png/xd3n2c08.png b/tests/Images/Input/Png/xd3n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..9e4a3ff7accf4453ddcd58318f7048b326b44ad2 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnP1SGpp+}Q-ASkfJR9T^zg78t&m77yfmc)B=- zRLpsM^&lsM0S}Wy>zj#xw-*UpyJ&w|_~YC|?Jc}4)(u=DKV%lXeNyXF;n2v$@6|4U rsD)ibc;6;z8n`u6{1- HoD!M<9fb>g literal 0 HcmV?d00001 From bc223bcd0b58a88791087f8bd14a50d60e7a770b Mon Sep 17 00:00:00 2001 From: Brian Popow <38701097+brianpopow@users.noreply.github.com> Date: Thu, 23 Apr 2020 18:20:18 +0200 Subject: [PATCH 160/213] Change CgBI chunk name to ProprietaryApple Co-Authored-By: James Jackson-South --- src/ImageSharp/Formats/Png/PngChunkType.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs index 67e5ccf557..015f6984d4 100644 --- a/src/ImageSharp/Formats/Png/PngChunkType.cs +++ b/src/ImageSharp/Formats/Png/PngChunkType.cs @@ -125,6 +125,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// Malformed chunk named CgBI produced by apple, which is not conform to the specification. /// Related issue is here https://github.com/SixLabors/ImageSharp/issues/410 /// - MalformedApple = 0x43674249 + ProprietaryApple = 0x43674249 } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 757b084816..0247dba351 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -215,8 +215,8 @@ namespace SixLabors.ImageSharp.Formats.Png case PngChunkType.End: this.isEndChunkReached = true; break; - case PngChunkType.MalformedApple: - PngThrowHelper.ThrowInvalidChunkType("Malformed Apple PNG detected! This PNG file is not conform to the specification and cannot be decoded."); + case PngChunkType.ProprietaryApple: + PngThrowHelper.ThrowInvalidChunkType("Proprietary Apple PNG detected! This PNG file is not conform to the specification and cannot be decoded."); break; } } From 6fb16cd44a9d20860bd1ebfcad5ba3131f1fbcbb Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 23 Apr 2020 18:30:00 +0200 Subject: [PATCH 161/213] Fix chunk type unit tests --- tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs index f3984ac823..3a207722bd 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Equal(PngChunkType.SignificantBits, GetType("sBIT")); Assert.Equal(PngChunkType.Histogram, GetType("hIST")); Assert.Equal(PngChunkType.SuggestedPalette, GetType("sPLT")); - Assert.Equal(PngChunkType.MalformedApple, GetType("CgBI")); + Assert.Equal(PngChunkType.ProprietaryApple, GetType("CgBI")); } private static PngChunkType GetType(string text) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index c4b5d0b4bf..6eb6e93db8 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -387,7 +387,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } }); Assert.NotNull(ex); - Assert.Contains("Malformed Apple PNG detected!", ex.Message); + Assert.Contains("Proprietary Apple PNG detected!", ex.Message); } [Theory] From b1afae8cdb209a67e226f61a6e8e5e5267638404 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 24 Apr 2020 12:08:49 +0200 Subject: [PATCH 162/213] Fix warning --- .../Drawing/DrawImageExtensionsTests.cs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs index 3f90412ae9..0aff95d994 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs @@ -1,17 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Linq; -using Moq; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Drawing; using SixLabors.ImageSharp.Tests.Processing; -using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; @@ -19,7 +12,6 @@ namespace SixLabors.ImageSharp.Tests.Drawing { public class DrawImageExtensionsTests : BaseImageOperationsExtensionTest { - [Fact] public void DrawImage_OpacityOnly_VerifyGraphicOptionsTakenFromContext() { @@ -28,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; this.operations.DrawImage(null, 0.5f); - var dip = this.Verify(); + DrawImageProcessor dip = this.Verify(); Assert.Equal(0.5, dip.Opacity); Assert.Equal(this.options.AlphaCompositionMode, dip.AlphaCompositionMode); @@ -43,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; this.operations.DrawImage(null, PixelColorBlendingMode.Multiply, 0.5f); - var dip = this.Verify(); + DrawImageProcessor dip = this.Verify(); Assert.Equal(0.5, dip.Opacity); Assert.Equal(this.options.AlphaCompositionMode, dip.AlphaCompositionMode); @@ -58,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; this.operations.DrawImage(null, Point.Empty, 0.5f); - var dip = this.Verify(); + DrawImageProcessor dip = this.Verify(); Assert.Equal(0.5, dip.Opacity); Assert.Equal(this.options.AlphaCompositionMode, dip.AlphaCompositionMode); @@ -73,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing this.options.ColorBlendingMode = PixelColorBlendingMode.Screen; this.operations.DrawImage(null, Point.Empty, PixelColorBlendingMode.Multiply, 0.5f); - var dip = this.Verify(); + DrawImageProcessor dip = this.Verify(); Assert.Equal(0.5, dip.Opacity); Assert.Equal(this.options.AlphaCompositionMode, dip.AlphaCompositionMode); From 6555e5499b88af9422c33bf3b7a18bd268a97ccf Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Apr 2020 20:12:34 +0100 Subject: [PATCH 163/213] Fix nuget package icon. --- Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 50c09fbb3c..388f873574 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -84,7 +84,7 @@ 8.0 en true - icon.png + sixlabors.imagesharp.128.png Apache-2.0 $(RepositoryUrl) true @@ -107,7 +107,7 @@ - + From 159b18b16d00f2cbff02761b3b3e7a5893061f5e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Apr 2020 22:42:01 +0100 Subject: [PATCH 164/213] Update package license details --- Directory.Build.props | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 388f873574..b82b3c1063 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -78,14 +78,14 @@ $(MSBuildThisFileDirectory)shared-infrastructure/SixLabors.snk - Copyright © Six Labors and Contributors + Copyright © Six Labors strict;IOperation true 8.0 en true sixlabors.imagesharp.128.png - Apache-2.0 + LICENSE.md $(RepositoryUrl) true git @@ -108,6 +108,7 @@ + From 6f2304bf6f9b80456c764aa06284b5b2f4ae26dc Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 26 Apr 2020 16:19:50 +0200 Subject: [PATCH 165/213] Identify now parses zTXt and iTXt chunks --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 6 ++ .../Formats/Png/PngMetadataTests.cs | 59 +++++++++++-------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 0247dba351..7d9011a55a 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -273,6 +273,12 @@ namespace SixLabors.ImageSharp.Formats.Png case PngChunkType.Text: this.ReadTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); break; + case PngChunkType.CompressedText: + this.ReadCompressedTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); + break; + case PngChunkType.InternationalText: + this.ReadInternationalTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); + break; case PngChunkType.End: this.isEndChunkReached = true; break; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index 5f5d5fd3d7..ee4e4f3c27 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -56,17 +56,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png using (Image image = provider.GetImage(new PngDecoder())) { PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Comment") && m.Value.Equals("comment")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Author") && m.Value.Equals("ImageSharp")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Copyright") && m.Value.Equals("ImageSharp")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Title") && m.Value.Equals("unittest")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Description") && m.Value.Equals("compressed-text")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("International") && m.Value.Equals("'e', mu'tlheghvam, ghaH yu'") && m.LanguageTag.Equals("x-klingon") && m.TranslatedKeyword.Equals("warning")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("International2") && m.Value.Equals("ИМАГЕШАРП") && m.LanguageTag.Equals("rus")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational") && m.Value.Equals("la plume de la mante") && m.LanguageTag.Equals("fra") && m.TranslatedKeyword.Equals("foobar")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational2") && m.Value.Equals("這是一個考驗") && m.LanguageTag.Equals("chinese")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoLang") && m.Value.Equals("this text chunk is missing a language tag")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoTranslatedKeyword") && m.Value.Equals("dieser chunk hat kein übersetztes Schlüßelwort")); + VerifyTextDataIsPresent(meta); } } @@ -85,17 +75,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png using (Image image = decoder.Decode(Configuration.Default, memoryStream)) { PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Comment") && m.Value.Equals("comment")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Author") && m.Value.Equals("ImageSharp")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Copyright") && m.Value.Equals("ImageSharp")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Title") && m.Value.Equals("unittest")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("Description") && m.Value.Equals("compressed-text")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("International") && m.Value.Equals("'e', mu'tlheghvam, ghaH yu'") && m.LanguageTag.Equals("x-klingon") && m.TranslatedKeyword.Equals("warning")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("International2") && m.Value.Equals("ИМАГЕШАРП") && m.LanguageTag.Equals("rus")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational") && m.Value.Equals("la plume de la mante") && m.LanguageTag.Equals("fra") && m.TranslatedKeyword.Equals("foobar")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational2") && m.Value.Equals("這是一個考驗") && m.LanguageTag.Equals("chinese")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoLang") && m.Value.Equals("this text chunk is missing a language tag")); - Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoTranslatedKeyword") && m.Value.Equals("dieser chunk hat kein übersetztes Schlüßelwort")); + VerifyTextDataIsPresent(meta); } } } @@ -178,7 +158,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png IgnoreMetadata = true }; - var testFile = TestFile.Create(TestImages.Png.Blur); + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); using (Image image = testFile.CreateRgba32Image(options)) { @@ -220,5 +200,38 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Equal(resolutionUnit, meta.ResolutionUnits); } } + + [Theory] + [InlineData(TestImages.Png.PngWithMetadata)] + public void Identify_ReadsTextData(string imagePath) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo imageInfo = Image.Identify(stream); + Assert.NotNull(imageInfo); + PngMetadata meta = imageInfo.Metadata.GetFormatMetadata(PngFormat.Instance); + VerifyTextDataIsPresent(meta); + } + } + + private static void VerifyTextDataIsPresent(PngMetadata meta) + { + Assert.NotNull(meta); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Comment") && m.Value.Equals("comment")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Author") && m.Value.Equals("ImageSharp")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Copyright") && m.Value.Equals("ImageSharp")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Title") && m.Value.Equals("unittest")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("Description") && m.Value.Equals("compressed-text")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("International") && m.Value.Equals("'e', mu'tlheghvam, ghaH yu'") && + m.LanguageTag.Equals("x-klingon") && m.TranslatedKeyword.Equals("warning")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("International2") && m.Value.Equals("ИМАГЕШАРП") && m.LanguageTag.Equals("rus")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational") && m.Value.Equals("la plume de la mante") && + m.LanguageTag.Equals("fra") && m.TranslatedKeyword.Equals("foobar")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("CompressedInternational2") && m.Value.Equals("這是一個考驗") && + m.LanguageTag.Equals("chinese")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoLang") && m.Value.Equals("this text chunk is missing a language tag")); + Assert.Contains(meta.TextData, m => m.Keyword.Equals("NoTranslatedKeyword") && m.Value.Equals("dieser chunk hat kein übersetztes Schlüßelwort")); + } } } From 03547d078c5d47a4bcc8185a869daf1237baeab0 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 26 Apr 2020 17:32:22 +0200 Subject: [PATCH 166/213] Identify reads now exif data --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 9 +++ .../Formats/Png/PngMetadataTests.cs | 58 ++++++++++++++++++ tests/Images/Input/Png/PngWithMetaData.png | Bin 805 -> 751 bytes 3 files changed, 67 insertions(+) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 7d9011a55a..a5bcff3b2b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -278,6 +278,15 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngChunkType.InternationalText: this.ReadInternationalTextChunk(pngMetadata, chunk.Data.Array.AsSpan(0, chunk.Length)); + break; + case PngChunkType.Exif: + if (!this.ignoreMetadata) + { + var exifData = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length); + metadata.ExifProfile = new ExifProfile(exifData); + } + break; case PngChunkType.End: this.isEndChunkReached = true; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index ee4e4f3c27..bf42066002 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -129,6 +130,40 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [WithFile(TestImages.Png.PngWithMetadata, PixelTypes.Rgba32)] + public void Decode_ReadsExifData(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + var decoder = new PngDecoder + { + IgnoreMetadata = false + }; + + using (Image image = provider.GetImage(decoder)) + { + Assert.NotNull(image.Metadata.ExifProfile); + ExifProfile exif = image.Metadata.ExifProfile; + VerifyExifDataIsPresent(exif); + } + } + + [Theory] + [WithFile(TestImages.Png.PngWithMetadata, PixelTypes.Rgba32)] + public void Decode_IgnoresExifData_WhenIgnoreMetadataIsTrue(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + var decoder = new PngDecoder + { + IgnoreMetadata = true + }; + + using (Image image = provider.GetImage(decoder)) + { + Assert.Null(image.Metadata.ExifProfile); + } + } + [Fact] public void Decode_IgnoreMetadataIsFalse_TextChunkIsRead() { @@ -215,6 +250,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [InlineData(TestImages.Png.PngWithMetadata)] + public void Identify_ReadsExifData(string imagePath) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + IImageInfo imageInfo = Image.Identify(stream); + Assert.NotNull(imageInfo); + Assert.NotNull(imageInfo.Metadata.ExifProfile); + ExifProfile exif = imageInfo.Metadata.ExifProfile; + VerifyExifDataIsPresent(exif); + } + } + + private static void VerifyExifDataIsPresent(ExifProfile exif) + { + Assert.Equal(1, exif.Values.Count); + IExifValue software = exif.GetValue(ExifTag.Software); + Assert.NotNull(software); + Assert.Equal("ImageSharp", software.Value); + } + private static void VerifyTextDataIsPresent(PngMetadata meta) { Assert.NotNull(meta); diff --git a/tests/Images/Input/Png/PngWithMetaData.png b/tests/Images/Input/Png/PngWithMetaData.png index af417b1f307329d72b536ab69170c1a06399d745..b5d0d344d7cf111b4f5d1784fac9b4fb1439b61a 100644 GIT binary patch delta 251 zcmZ3=_MUZu3J-IDPl#)2Qgob=n8m~ziHRx#2I{F1o@t(*S_~Wv3=E76hKx)M+(4ET z5UT>QXKrG8YH&tkQ2~&1JGcAg#9gH-(j~4DB`&GO$wiq3C7Jno49WSq1x2aF#i=Q} zC8-r9q8%#tCdV-PFj`Jt$tVLfCaoxuAuT^YDY1wlCsCmwr!+TJAthA-$j(j7D@ncM z6&^PE6XOC#TcCPrEhC^+$r+h>sl}-b&QSVg!^~$h)<4=1|x&vL^h2(ALIT{R%G;HbetT(B(2B5$dFc)$dHzw zpOjbx)N|T1MB{|!S>I3(&(IT|At!v#XnV3Uc>ZFSSvfU1eDZq61&nS$jk1P}49OXp zd8x&z49-xxVovog6zWSG$*yO&byLjPG(bE!!a%Y|ZmJF38lczFSb250k`njxg HN@xNA#T9AI From 386d942e1203439580ce9b182991a3f10016d125 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 26 Apr 2020 20:29:30 +0200 Subject: [PATCH 167/213] Fix png test image: Some text chunks unintentional changed to none compressed --- tests/Images/Input/Png/PngWithMetaData.png | Bin 751 -> 777 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/Images/Input/Png/PngWithMetaData.png b/tests/Images/Input/Png/PngWithMetaData.png index b5d0d344d7cf111b4f5d1784fac9b4fb1439b61a..2f167bd794368f92d6c86014deb14530cce4b4c5 100644 GIT binary patch delta 173 zcmaFQ+Q~NIudYf}NJNQCYH@N=W3VjE<87n56X>7#Y%v5*gC+^OF*bfO<}QhG?A7JnI|k;Td|uGvtKt8EsEi z2G3vYGApMhhfiM5xPZ|Os8QCCks&!FGcUC`mBATGSInutY4G`G&sYC46Pw%@br&!E VDSBGMQ0~kVz>=Y|Wb#y|C;)~DL6QIf delta 147 zcmeBVd(S%IuZnbuYeb1lYH@N=WlGHn1;bD^xFfL%U1!|Dh tU|>kj$jnPEPGxY0(k~lkKAW-r$&QAn4c#vqnqRJ*zH@<>)a3O{Q2 Date: Mon, 27 Apr 2020 11:55:47 +0200 Subject: [PATCH 168/213] Write gamma chunk before palette --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index fcbbc66974..34d5ee7739 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -149,10 +149,10 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(PngConstants.HeaderBytes); this.WriteHeaderChunk(stream); + this.WriteGammaChunk(stream); this.WritePaletteChunk(stream, quantized); this.WriteTransparencyChunk(stream, pngMetadata); this.WritePhysicalChunk(stream, metadata); - this.WriteGammaChunk(stream); this.WriteExifChunk(stream, metadata); this.WriteTextChunks(stream, pngMetadata); this.WriteDataChunks(image.Frames.RootFrame, quantized, stream); @@ -538,6 +538,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Writes the palette chunk to the stream. + /// Should be written before the first IDAT chunk. /// /// The pixel format. /// The containing image data. @@ -595,6 +596,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Writes the physical dimension information to the stream. + /// Should be written before IDAT chunk. /// /// The containing image data. /// The image metadata. @@ -716,6 +718,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Writes the gamma information to the stream. + /// Should be written before PLTE and IDAT chunk. /// /// The containing image data. private void WriteGammaChunk(Stream stream) @@ -733,6 +736,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Writes the transparency chunk to the stream. + /// Should be written after PLTE and before IDAT. /// /// The containing image data. /// The image metadata. From 7af7d41e1bda9160446e971d4e775b84ffacb123 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 27 Apr 2020 11:56:15 +0200 Subject: [PATCH 169/213] Add tests to ensure chunk order --- .../Formats/Png/PngEncoderTests.cs | 142 ++++++++++++++++-- tests/Images/Input/Png/PngWithMetaData.png | Bin 777 -> 60544 bytes 2 files changed, 130 insertions(+), 12 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 5a31d2d93c..0407ef295d 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. // ReSharper disable InconsistentNaming + +using System; +using System.Buffers.Binary; using System.IO; using System.Linq; @@ -18,6 +21,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { public class PngEncoderTests { + private static PngEncoder PngEncoder => new PngEncoder(); + public static readonly TheoryData PngBitDepthFiles = new TheoryData { @@ -234,8 +239,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { using (Stream stream = new MemoryStream()) { - var encoder = new PngEncoder(); - encoder.Encode(provider.GetImage(), stream); + PngEncoder.Encode(provider.GetImage(), stream); stream.Seek(0, SeekOrigin.Begin); @@ -281,7 +285,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png using (Image image = provider.GetImage()) using (var ms = new MemoryStream()) { - image.Save(ms, new PngEncoder()); + image.Save(ms, PngEncoder); byte[] data = ms.ToArray().Take(8).ToArray(); byte[] expected = @@ -304,14 +308,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [MemberData(nameof(RatioFiles))] public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { - var options = new PngEncoder(); - var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { using (var memStream = new MemoryStream()) { - input.Save(memStream, options); + input.Save(memStream, PngEncoder); memStream.Position = 0; using (var output = Image.Load(memStream)) @@ -329,14 +331,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [MemberData(nameof(PngBitDepthFiles))] public void Encode_PreserveBits(string imagePath, PngBitDepth pngBitDepth) { - var options = new PngEncoder(); - var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { using (var memStream = new MemoryStream()) { - input.Save(memStream, options); + input.Save(memStream, PngEncoder); memStream.Position = 0; using (var output = Image.Load(memStream)) @@ -353,8 +353,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [MemberData(nameof(PngTrnsFiles))] public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) { - var options = new PngEncoder(); - var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { @@ -363,7 +361,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png using (var memStream = new MemoryStream()) { - input.Save(memStream, options); + input.Save(memStream, PngEncoder); memStream.Position = 0; using (var output = Image.Load(memStream)) { @@ -404,6 +402,126 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Fact] + public void HeaderChunk_ComesFirst() + { + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + input.Save(memStream, PngEncoder); + memStream.Position = 0; + + // Skip header. + Span bytesSpan = memStream.ToArray().AsSpan(8); + BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + Assert.Equal(PngChunkType.Header, type); + } + + [Fact] + public void EndChunk_IsLast() + { + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + input.Save(memStream, PngEncoder); + memStream.Position = 0; + + // Skip header. + Span bytesSpan = memStream.ToArray().AsSpan(8); + + bool endChunkFound = false; + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + Assert.False(endChunkFound); + if (type == PngChunkType.End) + { + endChunkFound = true; + } + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + } + + [Theory] + [InlineData(PngChunkType.Gamma)] + [InlineData(PngChunkType.Chroma)] + [InlineData(PngChunkType.EmbeddedColorProfile)] + [InlineData(PngChunkType.SignificantBits)] + [InlineData(PngChunkType.StandardRgbColourSpace)] + public void Chunk_ComesBeforePlteAndIDat(object chunkTypeObj) + { + var chunkType = (PngChunkType)chunkTypeObj; + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + input.Save(memStream, PngEncoder); + memStream.Position = 0; + + // Skip header. + Span bytesSpan = memStream.ToArray().AsSpan(8); + + bool palFound = false; + bool dataFound = false; + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + if (chunkType == type) + { + Assert.False(palFound || dataFound, $"{chunkType} chunk should come before data and palette chunk"); + } + + switch (type) + { + case PngChunkType.Data: + dataFound = true; + break; + case PngChunkType.Palette: + palFound = true; + break; + } + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + } + + [Theory] + [InlineData(PngChunkType.Physical)] + [InlineData(PngChunkType.SuggestedPalette)] + public void Chunk_ComesBeforeIDat(object chunkTypeObj) + { + var chunkType = (PngChunkType)chunkTypeObj; + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + input.Save(memStream, PngEncoder); + memStream.Position = 0; + + // Skip header. + Span bytesSpan = memStream.ToArray().AsSpan(8); + + bool dataFound = false; + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + if (chunkType == type) + { + Assert.False(dataFound, $"{chunkType} chunk should come before data chunk"); + } + + if (type == PngChunkType.Data) + { + dataFound = true; + } + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + } + [Theory] [WithTestPatternImages(587, 821, PixelTypes.Rgba32)] [WithTestPatternImages(677, 683, PixelTypes.Rgba32)] diff --git a/tests/Images/Input/Png/PngWithMetaData.png b/tests/Images/Input/Png/PngWithMetaData.png index 2f167bd794368f92d6c86014deb14530cce4b4c5..b8a8b6d6b1f3118829f6a5e6b7798da71777459c 100644 GIT binary patch delta 60290 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

EulU*NE<2t^V14f# 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 vQchFr8wnRXh``fV00000NkvXXu0mjfEO;#X delta 72 zcmZp;$=t~{LB)_cz$e7DG$}gHNX&wPfq}EYBeIx*fm;}a85w5HkpK#^q&xaLGB9lH Y=l+w(x_Rfz)l8fWp00i_>zopr0Egcb6#xJL From 7161aa6f27aed77f4a119d96f386132c2a8b06f4 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 27 Apr 2020 12:41:23 +0200 Subject: [PATCH 170/213] Fix warning --- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 0407ef295d..fb5dc9a634 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. // ReSharper disable InconsistentNaming - using System; using System.Buffers.Binary; using System.IO; From 6545bbd77e90b18440f5d525995e5aafc387644e Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 27 Apr 2020 19:11:29 +0200 Subject: [PATCH 171/213] Remove obsolete PngTextProperties from png metadata --- src/ImageSharp/Formats/Png/PngMetadata.cs | 24 +---------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 341fc53edf..1e4567548b 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -91,34 +91,12 @@ namespace SixLabors.ImageSharp.Formats.Png public bool HasTransparency { get; set; } ///

- /// Gets or sets the collection of text data stored within the iTXt, tEXt, and zTXt chunks. + /// Gets or sets the collection of text data stored within the iTXt, tEXt, and zTXt chunks. /// Used for conveying textual information associated with the image. /// public IList TextData { get; set; } = new List(); - /// - /// Gets the list of png text properties for storing meta information about this image. - /// - public IList PngTextProperties { get; } = new List(); - /// public IDeepCloneable DeepClone() => new PngMetadata(this); - - internal bool TryGetPngTextProperty(string keyword, out PngTextData result) - { - for (int i = 0; i < this.TextData.Count; i++) - { - if (this.TextData[i].Keyword == keyword) - { - result = this.TextData[i]; - - return true; - } - } - - result = default; - - return false; - } } } From 8c9ec4f3a3a10ea8563ba201ec6f49a433435297 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 28 Apr 2020 10:15:34 +0200 Subject: [PATCH 172/213] Throw exception when width or height is zero --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index de5aa78843..e0d8b3cd96 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -6,7 +6,7 @@ using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; -using SixLabors.ImageSharp.Advanced; + using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Decodes the stream to the image. ///
/// The pixel format. - /// The stream containing image data. + /// The stream containing image data. /// The decoded image public Image Decode(Stream stream) where TPixel : unmanaged, IPixel @@ -241,6 +241,10 @@ namespace SixLabors.ImageSharp.Formats.Gif this.stream.Read(this.buffer, 0, 9); this.imageDescriptor = GifImageDescriptor.Parse(this.buffer); + if (this.imageDescriptor.Height == 0 || this.imageDescriptor.Width == 0) + { + GifThrowHelper.ThrowInvalidImageContentException("Width or height should not be 0"); + } } /// From 08b5c4cb8331fbba13a51ac7139975db83853851 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 28 Apr 2020 10:26:32 +0200 Subject: [PATCH 173/213] Change ImageFormatException to InvalidImageContentException --- .../Exceptions/InvalidImageContentException.cs | 14 ++++++++++++++ src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 4 +--- src/ImageSharp/Formats/Gif/GifDecoder.cs | 4 +--- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 4 +--- src/ImageSharp/Formats/Png/PngDecoder.cs | 4 +--- src/ImageSharp/Formats/Tga/TgaDecoder.cs | 4 +--- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs b/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs index 7069e89823..8be13919f1 100644 --- a/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs +++ b/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; + namespace SixLabors.ImageSharp { /// @@ -18,5 +20,17 @@ namespace SixLabors.ImageSharp : base(errorMessage) { } + + /// + /// Initializes a new instance of the class with the name of the + /// parameter that causes this exception. + /// + /// The error message that explains the reason for this exception. + /// The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) + /// if no inner exception is specified. + public InvalidImageContentException(string errorMessage, Exception innerException) + : base(errorMessage, innerException) + { + } } } diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index a956f19c72..cafe101060 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -43,9 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { Size dims = decoder.Dimensions; - // TODO: use InvalidImageContentException here, if we decide to define it - // https://github.com/SixLabors/ImageSharp/issues/1110 - throw new ImageFormatException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}. This error can happen for very large RLE bitmaps, which are not supported.", ex); + throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}. This error can happen for very large RLE bitmaps, which are not supported.", ex); } } diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index caa076553d..358d68e275 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -38,9 +38,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Size dims = decoder.Dimensions; - // TODO: use InvalidImageContentException here, if we decide to define it - // https://github.com/SixLabors/ImageSharp/issues/1110 - throw new ImageFormatException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index b1144508ec..424890cc2b 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -32,9 +32,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { (int w, int h) = (decoder.ImageWidth, decoder.ImageHeight); - // TODO: use InvalidImageContentException here, if we decide to define it - // https://github.com/SixLabors/ImageSharp/issues/1110 - throw new ImageFormatException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {w}x{h}.", ex); + throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {w}x{h}.", ex); } } diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index d605577e77..74903bcc25 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -54,9 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Png { Size dims = decoder.Dimensions; - // TODO: use InvalidImageContentException here, if we decide to define it - // https://github.com/SixLabors/ImageSharp/issues/1110 - throw new ImageFormatException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); } } diff --git a/src/ImageSharp/Formats/Tga/TgaDecoder.cs b/src/ImageSharp/Formats/Tga/TgaDecoder.cs index c3b8526ceb..b61a6ae28e 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoder.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoder.cs @@ -28,9 +28,7 @@ namespace SixLabors.ImageSharp.Formats.Tga { Size dims = decoder.Dimensions; - // TODO: use InvalidImageContentException here, if we decide to define it - // https://github.com/SixLabors/ImageSharp/issues/1110 - throw new ImageFormatException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); } } From b9a5c92cc1fc86f0348a3a1205a0c2af37d88e82 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 28 Apr 2020 10:48:28 +0200 Subject: [PATCH 174/213] Minor formatting change to get GitVersion going --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index de5aa78843..2e849ba1b7 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Decodes the stream to the image. /// /// The pixel format. - /// The stream containing image data. + /// The stream containing image data. /// The decoded image public Image Decode(Stream stream) where TPixel : unmanaged, IPixel From 08de04b505ca60620b969e7cf73f673df90bb378 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 28 Apr 2020 11:07:57 +0200 Subject: [PATCH 175/213] Change test expectations due to exception change --- tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 85cdf6d11a..f63fc0a16a 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp where TPixel : unmanaged, IPixel { provider.LimitAllocatorBufferCapacity().InPixelsSqrt(10); - ImageFormatException ex = Assert.Throws(() => provider.GetImage(BmpDecoder)); + InvalidImageContentException ex = Assert.Throws(() => provider.GetImage(BmpDecoder)); Assert.IsType(ex.InnerException); } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index b3a99aa1c0..80675a5eb5 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif where TPixel : unmanaged, IPixel { provider.LimitAllocatorBufferCapacity().InPixelsSqrt(10); - ImageFormatException ex = Assert.Throws(() => provider.GetImage(GifDecoder)); + InvalidImageContentException ex = Assert.Throws(() => provider.GetImage(GifDecoder)); Assert.IsType(ex.InnerException); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 25cf5dd376..a35bb177ce 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg where TPixel : unmanaged, IPixel { provider.LimitAllocatorBufferCapacity().InBytesSqrt(10); - ImageFormatException ex = Assert.Throws(() => provider.GetImage(JpegDecoder)); + InvalidImageContentException ex = Assert.Throws(() => provider.GetImage(JpegDecoder)); this.Output.WriteLine(ex.Message); Assert.IsType(ex.InnerException); } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 6eb6e93db8..72b27ec5d6 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -397,7 +397,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png where TPixel : unmanaged, IPixel { provider.LimitAllocatorBufferCapacity().InPixelsSqrt(10); - ImageFormatException ex = Assert.Throws(() => provider.GetImage(PngDecoder)); + InvalidImageContentException ex = Assert.Throws(() => provider.GetImage(PngDecoder)); Assert.IsType(ex.InnerException); } diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index 840bb55f20..6f886b73df 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -740,7 +740,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga where TPixel : unmanaged, IPixel { provider.LimitAllocatorBufferCapacity().InPixelsSqrt(10); - ImageFormatException ex = Assert.Throws(() => provider.GetImage(TgaDecoder)); + InvalidImageContentException ex = Assert.Throws(() => provider.GetImage(TgaDecoder)); Assert.IsType(ex.InnerException); } From 210c4817e45e328d18b5216d867418aa2ea50dff Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 28 Apr 2020 10:15:58 +0200 Subject: [PATCH 176/213] Additional gif test cases --- src/ImageSharp/Formats/Gif/README.md | 8 +- .../Formats/Gif/GifDecoderTests.cs | 82 ++++++++++-------- tests/ImageSharp.Tests/TestImages.cs | 7 ++ tests/Images/Input/Gif/image-zero-height.gif | Bin 0 -> 30 bytes tests/Images/Input/Gif/image-zero-size.gif | Bin 0 -> 30 bytes tests/Images/Input/Gif/image-zero-width.gif | Bin 0 -> 30 bytes tests/Images/Input/Gif/max-height.gif | Bin 0 -> 405 bytes tests/Images/Input/Gif/max-width.gif | Bin 0 -> 405 bytes 8 files changed, 59 insertions(+), 38 deletions(-) create mode 100644 tests/Images/Input/Gif/image-zero-height.gif create mode 100644 tests/Images/Input/Gif/image-zero-size.gif create mode 100644 tests/Images/Input/Gif/image-zero-width.gif create mode 100644 tests/Images/Input/Gif/max-height.gif create mode 100644 tests/Images/Input/Gif/max-width.gif diff --git a/src/ImageSharp/Formats/Gif/README.md b/src/ImageSharp/Formats/Gif/README.md index d47a4c6836..eeda20c06a 100644 --- a/src/ImageSharp/Formats/Gif/README.md +++ b/src/ImageSharp/Formats/Gif/README.md @@ -1,4 +1,6 @@ -Encoder/Decoder adapted and extended from: +Encoder/Decoder adapted and extended from: -https://github.com/yufeih/Nine.Imaging/ -https://imagetools.codeplex.com/ +- [Nine.Imaging](https://github.com/yufeih/Nine.Imaging/) +- [imagetools.codeplex](https://imagetools.codeplex.com/) + +A useful set of gif test images can be found at [pygif](https://github.com/robert-ancell/pygif/tree/master/test-suite) \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index b3a99aa1c0..199c6c0b25 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -2,11 +2,9 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Generic; using System.IO; using Microsoft.DotNet.RemoteExecutor; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; @@ -30,32 +28,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif TestImages.Gif.Giphy, TestImages.Gif.Kumin }; - public static readonly string[] BasicVerificationFiles = - { - TestImages.Gif.Cheers, - TestImages.Gif.Rings, - - // previously DecodeBadApplicationExtensionLength: - TestImages.Gif.Issues.BadAppExtLength, - TestImages.Gif.Issues.BadAppExtLength_2, - - // previously DecodeBadDescriptorDimensionsLength: - TestImages.Gif.Issues.BadDescriptorWidth - }; - - private static readonly Dictionary BasicVerificationFrameCount = - new Dictionary - { - [TestImages.Gif.Cheers] = 93, - [TestImages.Gif.Issues.BadDescriptorWidth] = 36, - }; - - public static readonly string[] BadAppExtFiles = - { - TestImages.Gif.Issues.BadAppExtLength, - TestImages.Gif.Issues.BadAppExtLength_2 - }; - [Theory] [WithFileCollection(nameof(MultiFrameTestFiles), PixelTypes.Rgba32)] public void Decode_VerifyAllFrames(TestImageProvider provider) @@ -100,15 +72,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } [Theory] - [WithFileCollection(nameof(BasicVerificationFiles), PixelTypes.Rgba32)] - public void Decode_VerifyRootFrameAndFrameCount(TestImageProvider provider) + [WithFile(TestImages.Gif.Cheers, PixelTypes.Rgba32, 93)] + [WithFile(TestImages.Gif.Rings, PixelTypes.Rgba32, 1)] + [WithFile(TestImages.Gif.Issues.BadDescriptorWidth, PixelTypes.Rgba32, 36)] + public void Decode_VerifyRootFrameAndFrameCount(TestImageProvider provider, int expectedFrameCount) where TPixel : unmanaged, IPixel { - if (!BasicVerificationFrameCount.TryGetValue(provider.SourceFileOrDescription, out int expectedFrameCount)) - { - expectedFrameCount = 1; - } - using (Image image = provider.GetImage()) { Assert.Equal(expectedFrameCount, image.Frames.Count); @@ -153,6 +122,35 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } } + [Theory] + [WithFile(TestImages.Gif.ZeroSize, PixelTypes.Rgba32)] + [WithFile(TestImages.Gif.ZeroWidth, PixelTypes.Rgba32)] + [WithFile(TestImages.Gif.ZeroHeight, PixelTypes.Rgba32)] + public void Decode_WithInvalidDimensions_DoesThrowException(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + System.Exception ex = Record.Exception( + () => + { + using Image image = provider.GetImage(GifDecoder); + }); + Assert.NotNull(ex); + Assert.Contains("Width or height should not be 0", ex.Message); + } + + [Theory] + [WithFile(TestImages.Gif.MaxWidth, PixelTypes.Rgba32, 65535, 1)] + [WithFile(TestImages.Gif.MaxHeight, PixelTypes.Rgba32, 1, 65535)] + public void Decode_WithMaxDimensions_Works(TestImageProvider provider, int expectedWidth, int expectedHeight) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(GifDecoder)) + { + Assert.Equal(expectedWidth, image.Width); + Assert.Equal(expectedHeight, image.Height); + } + } + [Fact] public void CanDecodeIntermingledImages() { @@ -172,6 +170,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } } + // https://github.com/SixLabors/ImageSharp/issues/405 + [Theory] + [WithFile(TestImages.Gif.Issues.BadAppExtLength, PixelTypes.Rgba32)] + [WithFile(TestImages.Gif.Issues.BadAppExtLength_2, PixelTypes.Rgba32)] + public void Issue405_BadApplicationExtensionBlockLength(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage()) + { + image.DebugSave(provider); + image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider); + } + } + [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] [WithFile(TestImages.Gif.Kumin, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index bec0c66242..141a8d1c38 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -397,6 +397,13 @@ namespace SixLabors.ImageSharp.Tests public const string Ratio1x4 = "Gif/base_1x4.gif"; public const string LargeComment = "Gif/large_comment.gif"; + // Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite + public const string ZeroSize = "Gif/image-zero-size.gif"; + public const string ZeroHeight = "Gif/image-zero-height.gif"; + public const string ZeroWidth = "Gif/image-zero-width.gif"; + public const string MaxWidth = "Gif/max-width.gif"; + public const string MaxHeight = "Gif/max-height.gif"; + public static class Issues { public const string BadAppExtLength = "Gif/issues/issue405_badappextlength252.gif"; diff --git a/tests/Images/Input/Gif/image-zero-height.gif b/tests/Images/Input/Gif/image-zero-height.gif new file mode 100644 index 0000000000000000000000000000000000000000..ddd3c43e885ff6c1a89cddd39d4ab477600edaf2 GIT binary patch literal 30 fcmZ?wbhEHbWMp7u_`t{j1poj4*8$NWPJ=Z7YKI1a literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Gif/image-zero-size.gif b/tests/Images/Input/Gif/image-zero-size.gif new file mode 100644 index 0000000000000000000000000000000000000000..8cb8c9e80f1d1d4878e2314ed9da92e61b219102 GIT binary patch literal 30 fcmZ?wbhEHbWMp7u_`t{j1poj4*8$NW&|nP!YJmoT literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Gif/image-zero-width.gif b/tests/Images/Input/Gif/image-zero-width.gif new file mode 100644 index 0000000000000000000000000000000000000000..ba61320c8a1bf1cb52572e845dc556724d333c32 GIT binary patch literal 30 gcmZ?wbhEHbWMp7u_`t{j1poj4*8$NCKoJIO0BMB=0RR91 literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Gif/max-height.gif b/tests/Images/Input/Gif/max-height.gif new file mode 100644 index 0000000000000000000000000000000000000000..586d03071bbb0384dfe23646ae4a2cd34b711e6b GIT binary patch literal 405 zcmV;G0c!q7Nk%w1VF3XD|MCC;00030|Ns900093000930|Ns90|Ns90EC2ui00991 z{{RF37`oj4Fv>}*y*TU5yZ>M)j$~<`XsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ z$!t2G(5Q4uty-_xtai)odcWYXcuX#v&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&s zy1Tr+zQ4f1!o$SH#>dFX%FE2n&d<=%($mz{*4NnC+S}aS-rwNi;^XAy=I7|?>g(+7 z?(gvN^7Hid_V@Vt`uqI-{{H|23LHqVpuvL(6DnNDu%W|;5F<*QNU@^Dix@L%+{m$F zqsNaRLy8oJq5$&6_xL>fFh*r_Y~2g9;r=w5ZXeNRujE z%CxD|r%}*y*TU5yZ>M)j$~<`XsWJk>%MR-&vb3yc&_h!@BhG{a7Zi~kI1BQ z$!t2G(5Q4uty-_xtai)odcWYXcuX#v&*-#z&2GEj@VIs;jK6uCK7Mva__cwzs&s zy1Tr+zQ4f1!o$SH#>dFX%FE2n&d<=%($mz{*4NnC+S}aS-rwNi;^XAy=I7|?>g(+7 z?(gvN^7Hid_V@Vt`uqI-{{H|23LHqVpuvL(6DnNDu%W|;5F<*QNU@^Dix@L%+{m$F zqsNaRLy8oJq5$&6_xL>fFh*r_Y~2g9;r=w5ZXeNRujE z%CxD|r% Date: Tue, 28 Apr 2020 12:31:57 +0200 Subject: [PATCH 177/213] Use ThrowHelper --- src/ImageSharp/Formats/Gif/GifDecoder.cs | 5 ++++- src/ImageSharp/Formats/Gif/GifThrowHelper.cs | 12 +++++++++++- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 5 ++++- src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs | 9 +++++++++ src/ImageSharp/Formats/Png/PngDecoder.cs | 5 ++++- src/ImageSharp/Formats/Png/PngThrowHelper.cs | 4 ++++ src/ImageSharp/Formats/Tga/TgaDecoder.cs | 5 ++++- src/ImageSharp/Formats/Tga/TgaThrowHelper.cs | 14 ++++++++++++-- 8 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 358d68e275..553163bd7e 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -38,7 +38,10 @@ namespace SixLabors.ImageSharp.Formats.Gif { Size dims = decoder.Dimensions; - throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + GifThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + + // Not reachable, as the previous statement will throw a exception. + return null; } } diff --git a/src/ImageSharp/Formats/Gif/GifThrowHelper.cs b/src/ImageSharp/Formats/Gif/GifThrowHelper.cs index 1d81008a01..1b20c9f64c 100644 --- a/src/ImageSharp/Formats/Gif/GifThrowHelper.cs +++ b/src/ImageSharp/Formats/Gif/GifThrowHelper.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Gif @@ -11,8 +12,17 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Cold path optimization for throwing 's /// /// The error message for the exception. - [MethodImpl(MethodImplOptions.NoInlining)] + [MethodImpl(InliningOptions.ColdPath)] public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage); + + /// + /// Cold path optimization for throwing 's. + /// + /// The error message for the exception. + /// The exception that is the cause of the current exception, or a null reference + /// if no inner exception is specified. + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowInvalidImageContentException(string errorMessage, Exception innerException) => throw new InvalidImageContentException(errorMessage, innerException); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index 424890cc2b..e60901d913 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -32,7 +32,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { (int w, int h) = (decoder.ImageWidth, decoder.ImageHeight); - throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {w}x{h}.", ex); + JpegThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {w}x{h}.", ex); + + // Not reachable, as the previous statement will throw a exception. + return null; } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs index dd44cb2d19..da4c3f9ee0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs @@ -15,6 +15,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg [MethodImpl(InliningOptions.ColdPath)] public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage); + /// + /// Cold path optimization for throwing 's. + /// + /// The error message for the exception. + /// The exception that is the cause of the current exception, or a null reference + /// if no inner exception is specified. + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowInvalidImageContentException(string errorMessage, Exception innerException) => throw new InvalidImageContentException(errorMessage, innerException); + /// /// Cold path optimization for throwing 's /// diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 74903bcc25..eceb4e592f 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -54,7 +54,10 @@ namespace SixLabors.ImageSharp.Formats.Png { Size dims = decoder.Dimensions; - throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + PngThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + + // Not reachable, as the previous statement will throw a exception. + return null; } } diff --git a/src/ImageSharp/Formats/Png/PngThrowHelper.cs b/src/ImageSharp/Formats/Png/PngThrowHelper.cs index b0a2571eae..a72a4a0d88 100644 --- a/src/ImageSharp/Formats/Png/PngThrowHelper.cs +++ b/src/ImageSharp/Formats/Png/PngThrowHelper.cs @@ -11,6 +11,10 @@ namespace SixLabors.ImageSharp.Formats.Png ///
internal static class PngThrowHelper { + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowInvalidImageContentException(string errorMessage, Exception innerException) + => throw new InvalidImageContentException(errorMessage, innerException); + [MethodImpl(InliningOptions.ColdPath)] public static void ThrowNoHeader() => throw new InvalidImageContentException("PNG Image does not contain a header chunk"); diff --git a/src/ImageSharp/Formats/Tga/TgaDecoder.cs b/src/ImageSharp/Formats/Tga/TgaDecoder.cs index b61a6ae28e..64dbdf58a9 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoder.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoder.cs @@ -28,7 +28,10 @@ namespace SixLabors.ImageSharp.Formats.Tga { Size dims = decoder.Dimensions; - throw new InvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + TgaThrowHelper.ThrowInvalidImageContentException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + + // Not reachable, as the previous statement will throw a exception. + return null; } } diff --git a/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs b/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs index 1714a2025e..fc158e781e 100644 --- a/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs +++ b/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs @@ -12,15 +12,25 @@ namespace SixLabors.ImageSharp.Formats.Tga /// Cold path optimization for throwing 's ///
/// The error message for the exception. - [MethodImpl(MethodImplOptions.NoInlining)] + [MethodImpl(InliningOptions.ColdPath)] public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage); + /// + /// Cold path optimization for throwing 's + /// + /// The error message for the exception. + /// The exception that is the cause of the current exception, or a null reference + /// if no inner exception is specified. + [MethodImpl(InliningOptions.ColdPath)] + public static void ThrowInvalidImageContentException(string errorMessage, Exception innerException) + => throw new InvalidImageContentException(errorMessage, innerException); + /// /// Cold path optimization for throwing 's /// /// The error message for the exception. - [MethodImpl(MethodImplOptions.NoInlining)] + [MethodImpl(InliningOptions.ColdPath)] public static void ThrowNotSupportedException(string errorMessage) => throw new NotSupportedException(errorMessage); } From 5854921c86f65313434aae8fcd18c4f3def2e65f Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 28 Apr 2020 17:33:16 +0200 Subject: [PATCH 178/213] Update external due to test file name changes --- tests/Images/External | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Images/External b/tests/Images/External index 6fdc6d19b1..0d1f91e2fe 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 6fdc6d19b101dc1c00a297d3e92257df60c413d0 +Subproject commit 0d1f91e2fe1491f6dc2c137a8ea20460fde4404c From a651570b48f517072c587458d91067cb8fd8ec9a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Apr 2020 10:33:54 +0100 Subject: [PATCH 179/213] Use enum over int. --- .../Formats/Png/IPngEncoderOptions.cs | 4 +- .../Formats/Png/PngCompressionLevel.cs | 81 +++++++++++++++++++ src/ImageSharp/Formats/Png/PngEncoder.cs | 38 +++------ .../Formats/Png/PngEncoderOptions.cs | 39 +++------ .../Formats/Png/Zlib/ZlibDeflateStream.cs | 5 +- .../Formats/Png/PngEncoderTests.cs | 18 ++++- 6 files changed, 118 insertions(+), 67 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/PngCompressionLevel.cs diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 87fd2582a5..0b27539c24 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -28,9 +28,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets the compression level 1-9. - /// Defaults to 6. + /// Defaults to . /// - int CompressionLevel { get; } + PngCompressionLevel CompressionLevel { get; } /// /// Gets the threshold of characters in text metadata, when compression should be used. diff --git a/src/ImageSharp/Formats/Png/PngCompressionLevel.cs b/src/ImageSharp/Formats/Png/PngCompressionLevel.cs new file mode 100644 index 0000000000..1d93884a33 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngCompressionLevel.cs @@ -0,0 +1,81 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// Provides enumeration of available PNG compression levels. + /// + public enum PngCompressionLevel + { + /// + /// Level 0. Equivalent to . + /// + Level0 = 0, + + /// + /// No compression. Equivalent to . + /// + NoCompression = Level0, + + /// + /// Level 1. Equivalent to . + /// + Level1 = 1, + + /// + /// Best speed compression level. + /// + BestSpeed = Level1, + + /// + /// Level 2. + /// + Level2 = 2, + + /// + /// Level 3. + /// + Level3 = 3, + + /// + /// Level 4. + /// + Level4 = 4, + + /// + /// Level 5. + /// + Level5 = 5, + + /// + /// Level 6. Equivalent to . + /// + Level6 = 6, + + /// + /// The default compression level. Equivalent to . + /// + DefaultCompression = Level6, + + /// + /// Level 7. + /// + Level7 = 7, + + /// + /// Level 8. + /// + Level8 = 8, + + /// + /// Level 9. Equivalent to . + /// + Level9 = 9, + + /// + /// Best compression level. Equivalent to . + /// + BestCompression = Level9, + } +} diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index e654036a8e..95c02b3481 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -13,43 +13,25 @@ namespace SixLabors.ImageSharp.Formats.Png /// public sealed class PngEncoder : IImageEncoder, IPngEncoderOptions { - /// - /// Gets or sets the number of bits per sample or per palette index (not per pixel). - /// Not all values are allowed for all values. - /// + /// public PngBitDepth? BitDepth { get; set; } - /// - /// Gets or sets the color type. - /// + /// public PngColorType? ColorType { get; set; } - /// - /// Gets or sets the filter method. - /// + /// public PngFilterMethod? FilterMethod { get; set; } - /// - /// Gets or sets the compression level 1-9. - /// Defaults to 6. - /// - public int CompressionLevel { get; set; } = 6; + /// + public PngCompressionLevel CompressionLevel { get; set; } = PngCompressionLevel.DefaultCompression; - /// - /// Gets or sets the threshold of characters in text metadata, when compression should be used. - /// Defaults to 1024. - /// + /// public int TextCompressionThreshold { get; set; } = 1024; - /// - /// Gets or sets the gamma value, that will be written the image. - /// + /// public float? Gamma { get; set; } - /// - /// Gets or sets quantizer for reducing the color count. - /// Defaults to the . - /// + /// public IQuantizer Quantizer { get; set; } /// @@ -57,9 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// public byte Threshold { get; set; } = byte.MaxValue; - /// - /// Gets or sets a value indicating whether this instance should write an Adam7 interlaced image. - /// + /// public PngInterlaceMode? InterlaceMethod { get; set; } /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index dd6c66cb7c..a6ac86d547 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -31,52 +31,31 @@ namespace SixLabors.ImageSharp.Formats.Png this.InterlaceMethod = source.InterlaceMethod; } - /// - /// Gets or sets the number of bits per sample or per palette index (not per pixel). - /// Not all values are allowed for all values. - /// + /// public PngBitDepth? BitDepth { get; set; } - /// - /// Gets or sets the color type. - /// + /// public PngColorType? ColorType { get; set; } - /// - /// Gets the filter method. - /// + /// public PngFilterMethod? FilterMethod { get; } - /// - /// Gets the compression level 1-9. - /// Defaults to 6. - /// - public int CompressionLevel { get; } + /// + public PngCompressionLevel CompressionLevel { get; } = PngCompressionLevel.DefaultCompression; /// public int TextCompressionThreshold { get; } - /// - /// Gets or sets the gamma value, that will be written the image. - /// - /// - /// The gamma value of the image. - /// + /// public float? Gamma { get; set; } - /// - /// Gets or sets the quantizer for reducing the color count. - /// + /// public IQuantizer Quantizer { get; set; } - /// - /// Gets the transparency threshold. - /// + /// public byte Threshold { get; } - /// - /// Gets or sets a value indicating whether this instance should write an Adam7 interlaced image. - /// + /// public PngInterlaceMode? InterlaceMethod { get; set; } } } diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs index c723b463f8..1829330331 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs @@ -46,9 +46,10 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// /// The memory allocator to use for buffer allocations. /// The stream to compress. - /// The compression level. - public ZlibDeflateStream(MemoryAllocator memoryAllocator, Stream stream, int compressionLevel) + /// The compression level. + public ZlibDeflateStream(MemoryAllocator memoryAllocator, Stream stream, PngCompressionLevel level) { + int compressionLevel = (int)level; this.rawStream = stream; // Write the zlib header : http://tools.ietf.org/html/rfc1950 diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index fb5dc9a634..2d5b2e25dd 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -65,9 +65,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png /// /// All types except Palette /// - public static readonly TheoryData CompressionLevels = new TheoryData + public static readonly TheoryData CompressionLevels + = new TheoryData { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + PngCompressionLevel.Level0, + PngCompressionLevel.Level1, + PngCompressionLevel.Level2, + PngCompressionLevel.Level3, + PngCompressionLevel.Level4, + PngCompressionLevel.Level5, + PngCompressionLevel.Level6, + PngCompressionLevel.Level7, + PngCompressionLevel.Level8, + PngCompressionLevel.Level9, }; public static readonly TheoryData PaletteSizes = new TheoryData @@ -150,7 +160,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [Theory] [WithTestPatternImages(nameof(CompressionLevels), 24, 24, PixelTypes.Rgba32)] - public void WorksWithAllCompressionLevels(TestImageProvider provider, int compressionLevel) + public void WorksWithAllCompressionLevels(TestImageProvider provider, PngCompressionLevel compressionLevel) where TPixel : unmanaged, IPixel { foreach (PngInterlaceMode interlaceMode in InterlaceMode) @@ -547,7 +557,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png PngFilterMethod pngFilterMethod, PngBitDepth bitDepth, PngInterlaceMode interlaceMode, - int compressionLevel = 6, + PngCompressionLevel compressionLevel = PngCompressionLevel.DefaultCompression, int paletteSize = 255, bool appendPngColorType = false, bool appendPngFilterMethod = false, From e343d36b8374ccdbee169c9932f116dc34d663d2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Apr 2020 11:24:28 +0100 Subject: [PATCH 180/213] Cleanup props/targets --- Directory.Build.props | 34 ++++++++++++++++++++++++++-------- src/Directory.Build.props | 2 +- tests/Directory.Build.props | 2 +- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b82b3c1063..b5f5f1279e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,7 +13,7 @@ $(MSBuildThisFileDirectory)artifacts/ - $(ImageSharpProjectCategory)/$(MSBuildProjectName) + $(SixLaborsProjectCategory)/$(MSBuildProjectName) https://github.com/SixLabors/ImageSharp/ @@ -45,22 +45,40 @@ --> - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_RUNTIME_INTRINSICS;SUPPORTS_CODECOVERAGE;SUPPORTS_HOTPATH + $(DefineConstants);SUPPORTS_MATHF + $(DefineConstants);SUPPORTS_HASHCODE + $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS + $(DefineConstants);SUPPORTS_SPAN_STREAM + $(DefineConstants);SUPPORTS_ENCODING_STRING + $(DefineConstants);SUPPORTS_RUNTIME_INTRINSICS + $(DefineConstants);SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_HOTPATH - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_MATHF + $(DefineConstants);SUPPORTS_HASHCODE + $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS + $(DefineConstants);SUPPORTS_SPAN_STREAM + $(DefineConstants);SUPPORTS_ENCODING_STRING + $(DefineConstants);SUPPORTS_CODECOVERAGE - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_MATHF + $(DefineConstants);SUPPORTS_CODECOVERAGE - $(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING;SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_MATHF + $(DefineConstants);SUPPORTS_HASHCODE + $(DefineConstants);SUPPORTS_SPAN_STREAM + $(DefineConstants);SUPPORTS_ENCODING_STRING + $(DefineConstants);SUPPORTS_CODECOVERAGE $(DefineConstants);SUPPORTS_CODECOVERAGE - $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_CODECOVERAGE + $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS + $(DefineConstants);SUPPORTS_CODECOVERAGE @@ -77,7 +95,6 @@ - $(MSBuildThisFileDirectory)shared-infrastructure/SixLabors.snk Copyright © Six Labors strict;IOperation true @@ -95,9 +112,10 @@ https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json; + true + $(MSBuildThisFileDirectory)shared-infrastructure/SixLabors.snk 00240000048000009400000006020000002400005253413100040000010001000147e6fe6766715eec6cfed61f1e7dcdbf69748a3e355c67e9d8dfd953acab1d5e012ba34b23308166fdc61ee1d0390d5f36d814a6091dd4b5ed9eda5a26afced924c683b4bfb4b3d64b0586a57eff9f02b1f84e3cb0ddd518bd1697f2c84dcbb97eb8bb5c7801be12112ed0ec86db934b0e9a5171e6bb1384b6d2f7d54dfa97 true - true diff --git a/src/Directory.Build.props b/src/Directory.Build.props index a78a75d428..87482af6f1 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -12,7 +12,7 @@ $(MSBuildAllProjects);$(MSBuildThisFileDirectory)..\Directory.Build.props - src + src diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 07d3332760..23a69362b0 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -12,7 +12,7 @@ $(MSBuildAllProjects);$(MSBuildThisFileDirectory)..\Directory.Build.props - tests + tests false From 6765f961203429d6336099d9639210f744962b7c Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 29 Apr 2020 12:35:52 +0200 Subject: [PATCH 181/213] Renamed enum to PngChunkFilter and also renamed enum names --- .../Formats/Png/IPngEncoderOptions.cs | 2 +- ...PngOptimizeMethod.cs => PngChunkFilter.cs} | 24 +++++++++---------- src/ImageSharp/Formats/Png/PngEncoder.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 10 ++++---- .../Formats/Png/PngEncoderOptions.cs | 2 +- .../Formats/Png/PngEncoderTests.cs | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) rename src/ImageSharp/Formats/Png/{PngOptimizeMethod.cs => PngChunkFilter.cs} (52%) diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 38c3484c81..d8af4c3260 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -61,6 +61,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets the optimize method. /// - PngOptimizeMethod? OptimizeMethod { get; } + PngChunkFilter? OptimizeMethod { get; } } } diff --git a/src/ImageSharp/Formats/Png/PngOptimizeMethod.cs b/src/ImageSharp/Formats/Png/PngChunkFilter.cs similarity index 52% rename from src/ImageSharp/Formats/Png/PngOptimizeMethod.cs rename to src/ImageSharp/Formats/Png/PngChunkFilter.cs index 7ad6646380..49af6ce594 100644 --- a/src/ImageSharp/Formats/Png/PngOptimizeMethod.cs +++ b/src/ImageSharp/Formats/Png/PngChunkFilter.cs @@ -9,41 +9,41 @@ namespace SixLabors.ImageSharp.Formats.Png /// Provides enumeration of available PNG optimization methods. ///
[Flags] - public enum PngOptimizeMethod + public enum PngChunkFilter { /// - /// With the None filter, the scanline is transmitted unmodified. + /// With the None filter, all chunks will be written. /// None = 0, /// - /// Suppress the physical dimension information chunk. + /// Excludes the physical dimension information chunk from encoding. /// - SuppressPhysicalChunk = 1, + ExcludePhysicalChunk = 1 << 0, /// - /// Suppress the gamma information chunk. + /// Excludes the gamma information chunk from encoding. /// - SuppressGammaChunk = 2, + ExcludeGammaChunk = 1 << 1, /// - /// Suppress the eXIf chunk. + /// Excludes the eXIf chunk from encoding. /// - SuppressExifChunk = 4, + ExcludeExifChunk = 1 << 2, /// - /// Suppress the tTXt, iTXt or zTXt chunk. + /// Excludes the tTXt, iTXt or zTXt chunk from encoding. /// - SuppressTextChunks = 8, + ExcludeTextChunks = 1 << 3, /// - /// Make funlly transparent pixels black. + /// Make fully transparent pixels black. /// MakeTransparentBlack = 16, /// /// All possible optimizations. /// - All = 31, + ExcludeAll = ExcludePhysicalChunk | ExcludeGammaChunk | ExcludeExifChunk | ExcludeTextChunks } } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 0f83d3d42e..c417ea872c 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets or sets the optimize method. /// - public PngOptimizeMethod? OptimizeMethod { get; set; } + public PngChunkFilter? OptimizeMethod { get; set; } /// /// Encodes the image to the specified stream from the . diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 47a377e67a..89c0b7f654 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Formats.Png PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); IndexedImageFrame quantized; - if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.MakeTransparentBlack) == PngOptimizeMethod.MakeTransparentBlack) + if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.MakeTransparentBlack) == PngChunkFilter.MakeTransparentBlack) { using (Image tempImage = image.Clone()) { @@ -182,7 +182,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.WriteHeaderChunk(stream); - if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressGammaChunk) != PngOptimizeMethod.SuppressGammaChunk) + if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.ExcludeGammaChunk) != PngChunkFilter.ExcludeGammaChunk) { this.WriteGammaChunk(stream); } @@ -190,17 +190,17 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePaletteChunk(stream, quantized); this.WriteTransparencyChunk(stream, pngMetadata); - if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressPhysicalChunk) != PngOptimizeMethod.SuppressPhysicalChunk) + if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.ExcludePhysicalChunk) != PngChunkFilter.ExcludePhysicalChunk) { this.WritePhysicalChunk(stream, metadata); } - if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressExifChunk) != PngOptimizeMethod.SuppressExifChunk) + if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.ExcludeExifChunk) != PngChunkFilter.ExcludeExifChunk) { this.WriteExifChunk(stream, metadata); } - if (((this.options.OptimizeMethod ?? PngOptimizeMethod.None) & PngOptimizeMethod.SuppressTextChunks) != PngOptimizeMethod.SuppressTextChunks) + if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.ExcludeTextChunks) != PngChunkFilter.ExcludeTextChunks) { this.WriteTextChunks(stream, pngMetadata); } diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index 89d7b0d5ef..4728b7ca83 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -83,6 +83,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets or sets a the optimize method. /// - public PngOptimizeMethod? OptimizeMethod { get; set; } + public PngChunkFilter? OptimizeMethod { get; set; } } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index ce734f6cfb..e2051ea277 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -235,7 +235,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png appendPngColorType: true, appendPixelType: true, appendPngBitDepth: true, - optimizeMethod: PngOptimizeMethod.All); + optimizeMethod: PngChunkFilter.ExcludeAll); } } @@ -589,7 +589,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png bool appendCompressionLevel = false, bool appendPaletteSize = false, bool appendPngBitDepth = false, - PngOptimizeMethod optimizeMethod = PngOptimizeMethod.None) + PngChunkFilter optimizeMethod = PngChunkFilter.None) where TPixel : unmanaged, IPixel { using (Image image = provider.GetImage()) From f257ef2217aa5a0bd8926de98a8191bd41f8bdbe Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 29 Apr 2020 14:05:48 +0200 Subject: [PATCH 182/213] Add tests for exclude filter --- .../Formats/Png/IPngEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoder.cs | 4 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 10 +- .../Formats/Png/PngEncoderOptions.cs | 4 +- .../Formats/Png/PngEncoderTests.Chunks.cs | 242 ++++++++++++++++++ .../Formats/Png/PngEncoderTests.cs | 128 +-------- 6 files changed, 255 insertions(+), 135 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index d8af4c3260..f5113d3d99 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -61,6 +61,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets the optimize method. /// - PngChunkFilter? OptimizeMethod { get; } + PngChunkFilter? ChunkFilter { get; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index c417ea872c..d2eba47dea 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -63,9 +63,9 @@ namespace SixLabors.ImageSharp.Formats.Png public PngInterlaceMode? InterlaceMethod { get; set; } /// - /// Gets or sets the optimize method. + /// Gets or sets the chunk filter. This can be used to exclude some ancillary chunks from being written. /// - public PngChunkFilter? OptimizeMethod { get; set; } + public PngChunkFilter? ChunkFilter { get; set; } /// /// Encodes the image to the specified stream from the . diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 89c0b7f654..1af5929fec 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Formats.Png PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); IndexedImageFrame quantized; - if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.MakeTransparentBlack) == PngChunkFilter.MakeTransparentBlack) + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.MakeTransparentBlack) == PngChunkFilter.MakeTransparentBlack) { using (Image tempImage = image.Clone()) { @@ -182,7 +182,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.WriteHeaderChunk(stream); - if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.ExcludeGammaChunk) != PngChunkFilter.ExcludeGammaChunk) + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeGammaChunk) != PngChunkFilter.ExcludeGammaChunk) { this.WriteGammaChunk(stream); } @@ -190,17 +190,17 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePaletteChunk(stream, quantized); this.WriteTransparencyChunk(stream, pngMetadata); - if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.ExcludePhysicalChunk) != PngChunkFilter.ExcludePhysicalChunk) + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludePhysicalChunk) != PngChunkFilter.ExcludePhysicalChunk) { this.WritePhysicalChunk(stream, metadata); } - if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.ExcludeExifChunk) != PngChunkFilter.ExcludeExifChunk) + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeExifChunk) != PngChunkFilter.ExcludeExifChunk) { this.WriteExifChunk(stream, metadata); } - if (((this.options.OptimizeMethod ?? PngChunkFilter.None) & PngChunkFilter.ExcludeTextChunks) != PngChunkFilter.ExcludeTextChunks) + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeTextChunks) != PngChunkFilter.ExcludeTextChunks) { this.WriteTextChunks(stream, pngMetadata); } diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index 4728b7ca83..f11a232698 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.Quantizer = source.Quantizer; this.Threshold = source.Threshold; this.InterlaceMethod = source.InterlaceMethod; - this.OptimizeMethod = source.OptimizeMethod; + this.ChunkFilter = source.ChunkFilter; } /// @@ -83,6 +83,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets or sets a the optimize method. /// - public PngChunkFilter? OptimizeMethod { get; set; } + public PngChunkFilter? ChunkFilter { get; set; } } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs new file mode 100644 index 0000000000..9d28fd89b0 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs @@ -0,0 +1,242 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.Formats.Png +{ + public partial class PngEncoderTests + { + [Fact] + public void HeaderChunk_ComesFirst() + { + // arrange + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + + // act + input.Save(memStream, PngEncoder); + + // assert + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + Assert.Equal(PngChunkType.Header, type); + } + + [Fact] + public void EndChunk_IsLast() + { + // arrange + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + + // act + input.Save(memStream, PngEncoder); + + // assert + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + bool endChunkFound = false; + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + Assert.False(endChunkFound); + if (type == PngChunkType.End) + { + endChunkFound = true; + } + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + } + + [Theory] + [InlineData(PngChunkType.Gamma)] + [InlineData(PngChunkType.Chroma)] + [InlineData(PngChunkType.EmbeddedColorProfile)] + [InlineData(PngChunkType.SignificantBits)] + [InlineData(PngChunkType.StandardRgbColourSpace)] + public void Chunk_ComesBeforePlteAndIDat(object chunkTypeObj) + { + // arrange + var chunkType = (PngChunkType)chunkTypeObj; + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + + // act + input.Save(memStream, PngEncoder); + + // assert + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + bool palFound = false; + bool dataFound = false; + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + if (chunkType == type) + { + Assert.False(palFound || dataFound, $"{chunkType} chunk should come before data and palette chunk"); + } + + switch (type) + { + case PngChunkType.Data: + dataFound = true; + break; + case PngChunkType.Palette: + palFound = true; + break; + } + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + } + + [Theory] + [InlineData(PngChunkType.Physical)] + [InlineData(PngChunkType.SuggestedPalette)] + public void Chunk_ComesBeforeIDat(object chunkTypeObj) + { + // arrange + var chunkType = (PngChunkType)chunkTypeObj; + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + + // act + input.Save(memStream, PngEncoder); + + // assert + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + bool dataFound = false; + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + if (chunkType == type) + { + Assert.False(dataFound, $"{chunkType} chunk should come before data chunk"); + } + + if (type == PngChunkType.Data) + { + dataFound = true; + } + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + } + + [Theory] + [InlineData(PngChunkFilter.ExcludeGammaChunk)] + [InlineData(PngChunkFilter.ExcludeExifChunk)] + [InlineData(PngChunkFilter.ExcludePhysicalChunk)] + [InlineData(PngChunkFilter.ExcludeTextChunks)] + [InlineData(PngChunkFilter.ExcludeAll)] + public void ExcludeFilter_Works(object filterObj) + { + // arrange + var chunkFilter = (PngChunkFilter)filterObj; + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + var encoder = new PngEncoder() { ChunkFilter = chunkFilter, TextCompressionThreshold = 8 }; + var excludedChunkTypes = new List(); + switch (chunkFilter) + { + case PngChunkFilter.ExcludeGammaChunk: + excludedChunkTypes.Add(PngChunkType.Gamma); + break; + case PngChunkFilter.ExcludeExifChunk: + excludedChunkTypes.Add(PngChunkType.Exif); + break; + case PngChunkFilter.ExcludePhysicalChunk: + excludedChunkTypes.Add(PngChunkType.Physical); + break; + case PngChunkFilter.ExcludeTextChunks: + excludedChunkTypes.Add(PngChunkType.Text); + excludedChunkTypes.Add(PngChunkType.InternationalText); + excludedChunkTypes.Add(PngChunkType.CompressedText); + break; + case PngChunkFilter.ExcludeAll: + excludedChunkTypes.Add(PngChunkType.Gamma); + excludedChunkTypes.Add(PngChunkType.Exif); + excludedChunkTypes.Add(PngChunkType.Physical); + excludedChunkTypes.Add(PngChunkType.Text); + excludedChunkTypes.Add(PngChunkType.InternationalText); + excludedChunkTypes.Add(PngChunkType.CompressedText); + break; + } + + // act + input.Save(memStream, encoder); + + // assert + Assert.True(excludedChunkTypes.Count > 0); + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var chunkType = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + Assert.False(excludedChunkTypes.Contains(chunkType), $"{chunkType} chunk should have been excluded"); + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + } + + [Fact] + public void ExcludeFilter_WithNone_DoesNotExcludeChunks() + { + // arrange + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + var encoder = new PngEncoder() { ChunkFilter = PngChunkFilter.None, TextCompressionThreshold = 8 }; + var expectedChunkTypes = new List() + { + PngChunkType.Header, + PngChunkType.Gamma, + PngChunkType.Palette, + PngChunkType.Transparency, + PngChunkType.InternationalText, + PngChunkType.Text, + PngChunkType.CompressedText, + PngChunkType.Exif, + PngChunkType.Physical, + PngChunkType.Data, + PngChunkType.End, + }; + + // act + input.Save(memStream, encoder); + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var chunkType = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + Assert.True(expectedChunkTypes.Contains(chunkType), $"{chunkType} chunk should have been present"); + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index e2051ea277..cf5f5c4dba 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. // ReSharper disable InconsistentNaming -using System; -using System.Buffers.Binary; using System.IO; using System.Linq; @@ -18,7 +16,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Png { - public class PngEncoderTests + public partial class PngEncoderTests { private static PngEncoder PngEncoder => new PngEncoder(); @@ -221,7 +219,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [WithTestPatternImages(24, 24, PixelTypes.Rgb48, PngColorType.Grayscale, PngBitDepth.Bit16)] [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit16)] - public void WorksWithAllBitDepthsOptimized(TestImageProvider provider, PngColorType pngColorType, PngBitDepth pngBitDepth) + public void WorksWithAllBitDepthsAndExcludeAllFilter(TestImageProvider provider, PngColorType pngColorType, PngBitDepth pngBitDepth) where TPixel : unmanaged, IPixel { foreach (PngInterlaceMode interlaceMode in InterlaceMode) @@ -435,126 +433,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } - [Fact] - public void HeaderChunk_ComesFirst() - { - var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); - using Image input = testFile.CreateRgba32Image(); - using var memStream = new MemoryStream(); - input.Save(memStream, PngEncoder); - memStream.Position = 0; - - // Skip header. - Span bytesSpan = memStream.ToArray().AsSpan(8); - BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); - var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); - Assert.Equal(PngChunkType.Header, type); - } - - [Fact] - public void EndChunk_IsLast() - { - var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); - using Image input = testFile.CreateRgba32Image(); - using var memStream = new MemoryStream(); - input.Save(memStream, PngEncoder); - memStream.Position = 0; - - // Skip header. - Span bytesSpan = memStream.ToArray().AsSpan(8); - - bool endChunkFound = false; - while (bytesSpan.Length > 0) - { - int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); - var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); - Assert.False(endChunkFound); - if (type == PngChunkType.End) - { - endChunkFound = true; - } - - bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); - } - } - - [Theory] - [InlineData(PngChunkType.Gamma)] - [InlineData(PngChunkType.Chroma)] - [InlineData(PngChunkType.EmbeddedColorProfile)] - [InlineData(PngChunkType.SignificantBits)] - [InlineData(PngChunkType.StandardRgbColourSpace)] - public void Chunk_ComesBeforePlteAndIDat(object chunkTypeObj) - { - var chunkType = (PngChunkType)chunkTypeObj; - var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); - using Image input = testFile.CreateRgba32Image(); - using var memStream = new MemoryStream(); - input.Save(memStream, PngEncoder); - memStream.Position = 0; - - // Skip header. - Span bytesSpan = memStream.ToArray().AsSpan(8); - - bool palFound = false; - bool dataFound = false; - while (bytesSpan.Length > 0) - { - int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); - var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); - if (chunkType == type) - { - Assert.False(palFound || dataFound, $"{chunkType} chunk should come before data and palette chunk"); - } - - switch (type) - { - case PngChunkType.Data: - dataFound = true; - break; - case PngChunkType.Palette: - palFound = true; - break; - } - - bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); - } - } - - [Theory] - [InlineData(PngChunkType.Physical)] - [InlineData(PngChunkType.SuggestedPalette)] - public void Chunk_ComesBeforeIDat(object chunkTypeObj) - { - var chunkType = (PngChunkType)chunkTypeObj; - var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); - using Image input = testFile.CreateRgba32Image(); - using var memStream = new MemoryStream(); - input.Save(memStream, PngEncoder); - memStream.Position = 0; - - // Skip header. - Span bytesSpan = memStream.ToArray().AsSpan(8); - - bool dataFound = false; - while (bytesSpan.Length > 0) - { - int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); - var type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); - if (chunkType == type) - { - Assert.False(dataFound, $"{chunkType} chunk should come before data chunk"); - } - - if (type == PngChunkType.Data) - { - dataFound = true; - } - - bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); - } - } - [Theory] [WithTestPatternImages(587, 821, PixelTypes.Rgba32)] [WithTestPatternImages(677, 683, PixelTypes.Rgba32)] @@ -602,7 +480,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png BitDepth = bitDepth, Quantizer = new WuQuantizer(new QuantizerOptions { MaxColors = paletteSize }), InterlaceMethod = interlaceMode, - OptimizeMethod = optimizeMethod, + ChunkFilter = optimizeMethod, }; string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; From f04e836587a87524d4cfe0ff19f54b50459c9c79 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 29 Apr 2020 14:29:57 +0200 Subject: [PATCH 183/213] MakeTransparentBlack is now a png encoder option --- src/ImageSharp/Formats/Png/IPngEncoderOptions.cs | 5 +++++ src/ImageSharp/Formats/Png/PngChunkFilter.cs | 5 ----- src/ImageSharp/Formats/Png/PngEncoder.cs | 5 +++++ src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 ++-- src/ImageSharp/Formats/Png/PngEncoderOptions.cs | 4 ++++ 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index f5113d3d99..be510b1562 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -62,5 +62,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets the optimize method. /// PngChunkFilter? ChunkFilter { get; } + + /// + /// Gets a value indicating whether fully transparent pixels should be converted to black pixels. + /// + bool MakeTransparentBlack { get; } } } diff --git a/src/ImageSharp/Formats/Png/PngChunkFilter.cs b/src/ImageSharp/Formats/Png/PngChunkFilter.cs index 49af6ce594..f859d44dac 100644 --- a/src/ImageSharp/Formats/Png/PngChunkFilter.cs +++ b/src/ImageSharp/Formats/Png/PngChunkFilter.cs @@ -36,11 +36,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// ExcludeTextChunks = 1 << 3, - /// - /// Make fully transparent pixels black. - /// - MakeTransparentBlack = 16, - /// /// All possible optimizations. /// diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index d2eba47dea..197506ffd5 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -67,6 +67,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// public PngChunkFilter? ChunkFilter { get; set; } + /// + /// Gets or sets a value indicating whether fully transparent pixels should be converted to black pixels. + /// + public bool MakeTransparentBlack { get; set; } + /// /// Encodes the image to the specified stream from the . /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 1af5929fec..416c26b0f0 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -7,7 +7,7 @@ using System.Buffers.Binary; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Advanced; + using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Formats.Png PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); IndexedImageFrame quantized; - if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.MakeTransparentBlack) == PngChunkFilter.MakeTransparentBlack) + if (this.options.MakeTransparentBlack) { using (Image tempImage = image.Clone()) { diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index f11a232698..ba8a897cef 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -30,6 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.Threshold = source.Threshold; this.InterlaceMethod = source.InterlaceMethod; this.ChunkFilter = source.ChunkFilter; + this.MakeTransparentBlack = source.MakeTransparentBlack; } /// @@ -84,5 +85,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets or sets a the optimize method. /// public PngChunkFilter? ChunkFilter { get; set; } + + /// + public bool MakeTransparentBlack { get; set; } } } From 624591c421069484f6b1a9b5f61cf6b504cb6db6 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 29 Apr 2020 14:44:39 +0200 Subject: [PATCH 184/213] Refactor --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 81 ++++++++++++-------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 416c26b0f0..7d00e20e4b 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -144,6 +144,34 @@ namespace SixLabors.ImageSharp.Formats.Png PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); + IndexedImageFrame quantized = this.CreateQuantizedImage(image); + + stream.Write(PngConstants.HeaderBytes); + + this.WriteHeaderChunk(stream); + this.WriteGammaChunk(stream); + this.WritePaletteChunk(stream, quantized); + this.WriteTransparencyChunk(stream, pngMetadata); + this.WritePhysicalChunk(stream, metadata); + this.WriteExifChunk(stream, metadata); + this.WriteTextChunks(stream, pngMetadata); + this.WriteDataChunks(image.Frames.RootFrame, quantized, stream); + this.WriteEndChunk(stream); + + stream.Flush(); + + quantized?.Dispose(); + } + + /// + /// Creates the quantized image and sets calculates and sets the bit depth. + /// + /// The type of the pixel. + /// The image to quantize. + /// The quantized image. + private IndexedImageFrame CreateQuantizedImage(Image image) + where TPixel : unmanaged, IPixel + { IndexedImageFrame quantized; if (this.options.MakeTransparentBlack) { @@ -178,38 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, image, quantized); } - stream.Write(PngConstants.HeaderBytes); - - this.WriteHeaderChunk(stream); - - if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeGammaChunk) != PngChunkFilter.ExcludeGammaChunk) - { - this.WriteGammaChunk(stream); - } - - this.WritePaletteChunk(stream, quantized); - this.WriteTransparencyChunk(stream, pngMetadata); - - if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludePhysicalChunk) != PngChunkFilter.ExcludePhysicalChunk) - { - this.WritePhysicalChunk(stream, metadata); - } - - if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeExifChunk) != PngChunkFilter.ExcludeExifChunk) - { - this.WriteExifChunk(stream, metadata); - } - - if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeTextChunks) != PngChunkFilter.ExcludeTextChunks) - { - this.WriteTextChunks(stream, pngMetadata); - } - - this.WriteDataChunks(image.Frames.RootFrame, quantized, stream); - this.WriteEndChunk(stream); - stream.Flush(); - - quantized?.Dispose(); + return quantized; } /// @@ -652,6 +649,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image metadata. private void WritePhysicalChunk(Stream stream, ImageMetadata meta) { + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludePhysicalChunk) == PngChunkFilter.ExcludePhysicalChunk) + { + return; + } + PhysicalChunkData.FromMetadata(meta).WriteTo(this.chunkDataBuffer); this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer, 0, PhysicalChunkData.Size); @@ -664,6 +666,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image metadata. private void WriteExifChunk(Stream stream, ImageMetadata meta) { + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeExifChunk) == PngChunkFilter.ExcludeExifChunk) + { + return; + } + if (meta.ExifProfile is null || meta.ExifProfile.Values.Count == 0) { return; @@ -681,6 +688,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image metadata. private void WriteTextChunks(Stream stream, PngMetadata meta) { + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeTextChunks) == PngChunkFilter.ExcludeTextChunks) + { + return; + } + const int MaxLatinCode = 255; for (int i = 0; i < meta.TextData.Count; i++) { @@ -773,6 +785,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// The containing image data. private void WriteGammaChunk(Stream stream) { + if (((this.options.ChunkFilter ?? PngChunkFilter.None) & PngChunkFilter.ExcludeGammaChunk) == PngChunkFilter.ExcludeGammaChunk) + { + return; + } + if (this.options.Gamma > 0) { // 4-byte unsigned integer of gamma * 100,000. From 5e479b1dc5505729c06b1a944fee04769a51cf70 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Apr 2020 17:38:44 +0100 Subject: [PATCH 185/213] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 68c5746528..bd9007e4f9 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standa - ImageSharp is licensed under the [GNU Affero General Public License v3](https://www.gnu.org/licenses/agpl-3.0) - An alternative Commercial License can be purchased for Closed Source projects and applications. Please visit https://sixlabors.com/pricing for details. -- Open Source projects who whave taken a dependency on ImageSharp prior to adoption of the AGPL v3 license are permitted to use ImageSharp (including all future versions) under the previous [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). +- Open Source projects who have taken a dependency on ImageSharp prior to adoption of the AGPL v3 license are permitted to use ImageSharp (including all future versions) under the previous [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). ## Documentation From a86713f25ebe5ec3dd4036f744aa72fd3d765a7f Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 29 Apr 2020 18:48:07 +0200 Subject: [PATCH 186/213] Add tests for make transparent black option --- .../Formats/Png/PngEncoderTests.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index cf5f5c4dba..dff6cb8f8c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -380,6 +380,68 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [InlineData(PngColorType.Palette)] + [InlineData(PngColorType.Rgb)] + [InlineData(PngColorType.RgbWithAlpha)] + [InlineData(PngColorType.Grayscale)] + [InlineData(PngColorType.GrayscaleWithAlpha)] + public void Encode_WithMakeTransparentBlackOption_Works(PngColorType colorType) + { + // arrange + var image = new Image(50, 50); + var encoder = new PngEncoder() + { + MakeTransparentBlack = true, + ColorType = colorType + }; + Rgba32 rgba32 = Color.Blue; + for (int y = 0; y < image.Height; y++) + { + System.Span rowSpan = image.GetPixelRowSpan(y); + + // Half of the test image should be transparent. + if (y > 25) + { + rgba32.A = 0; + } + + for (int x = 0; x < image.Width; x++) + { + rowSpan[x].FromRgba32(rgba32); + } + } + + // act + using var memStream = new MemoryStream(); + image.Save(memStream, encoder); + + // assert + memStream.Position = 0; + using var actual = Image.Load(memStream); + Rgba32 expectedColor = Color.Blue; + if (colorType == PngColorType.Grayscale || colorType == PngColorType.GrayscaleWithAlpha) + { + var luminance = ImageMaths.Get8BitBT709Luminance(expectedColor.R, expectedColor.G, expectedColor.B); + expectedColor = new Rgba32(luminance, luminance, luminance); + } + + for (int y = 0; y < actual.Height; y++) + { + System.Span rowSpan = actual.GetPixelRowSpan(y); + + if (y > 25) + { + expectedColor = Color.Black; + } + + for (int x = 0; x < actual.Width; x++) + { + Assert.Equal(expectedColor, rowSpan[x]); + } + } + } + [Theory] [MemberData(nameof(PngTrnsFiles))] public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) From 8ca9b97c9e182b7792a25d1d1b3a70b18b35417b Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 29 Apr 2020 18:58:43 +0200 Subject: [PATCH 187/213] MakeTransparentBlack option now work with all png color type --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 109 ++++++++++--------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7d00e20e4b..d8509548ad 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -144,7 +144,14 @@ namespace SixLabors.ImageSharp.Formats.Png PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); - IndexedImageFrame quantized = this.CreateQuantizedImage(image); + Image clonedImage = null; + if (this.options.MakeTransparentBlack) + { + clonedImage = image.Clone(); + MakeTransparentPixelsBlack(clonedImage); + } + + IndexedImageFrame quantized = this.CreateQuantizedImage(image, clonedImage); stream.Write(PngConstants.HeaderBytes); @@ -155,12 +162,55 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePhysicalChunk(stream, metadata); this.WriteExifChunk(stream, metadata); this.WriteTextChunks(stream, pngMetadata); - this.WriteDataChunks(image.Frames.RootFrame, quantized, stream); + this.WriteDataChunks(this.options.MakeTransparentBlack ? clonedImage : image, quantized, stream); this.WriteEndChunk(stream); stream.Flush(); quantized?.Dispose(); + clonedImage?.Dispose(); + } + + /// + public void Dispose() + { + this.previousScanline?.Dispose(); + this.currentScanline?.Dispose(); + this.subFilter?.Dispose(); + this.averageFilter?.Dispose(); + this.paethFilter?.Dispose(); + this.filterBuffer?.Dispose(); + + this.previousScanline = null; + this.currentScanline = null; + this.subFilter = null; + this.averageFilter = null; + this.paethFilter = null; + this.filterBuffer = null; + } + + /// + /// Makes transparent pixels black. + /// + /// The type of the pixel. + /// The cloned image where the transparent pixels will be changed. + private static void MakeTransparentPixelsBlack(Image image) + where TPixel : unmanaged, IPixel + { + Rgba32 rgba32 = default; + for (int y = 0; y < image.Height; y++) + { + Span span = image.GetPixelRowSpan(y); + for (int x = 0; x < image.Width; x++) + { + span[x].ToRgba32(ref rgba32); + + if (rgba32.A == 0) + { + span[x].FromRgba32(Color.Black); + } + } + } } /// @@ -168,37 +218,16 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The type of the pixel. /// The image to quantize. + /// Cloned image with transparent pixels are changed to black. /// The quantized image. - private IndexedImageFrame CreateQuantizedImage(Image image) + private IndexedImageFrame CreateQuantizedImage(Image image, Image clonedImage) where TPixel : unmanaged, IPixel { IndexedImageFrame quantized; if (this.options.MakeTransparentBlack) { - using (Image tempImage = image.Clone()) - { - for (int y = 0; y < image.Height; y++) - { - Span span = tempImage.GetPixelRowSpan(y); - for (int x = 0; x < image.Width; x++) - { - Rgba32 rgba32 = default; - span[x].ToRgba32(ref rgba32); - - if (rgba32.A == 0) - { - rgba32.R = 0; - rgba32.G = 0; - rgba32.B = 0; - } - - span[x].FromRgba32(rgba32); - } - } - - quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, tempImage); - this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, tempImage, quantized); - } + quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, clonedImage); + this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, clonedImage, quantized); } else { @@ -209,24 +238,6 @@ namespace SixLabors.ImageSharp.Formats.Png return quantized; } - /// - public void Dispose() - { - this.previousScanline?.Dispose(); - this.currentScanline?.Dispose(); - this.subFilter?.Dispose(); - this.averageFilter?.Dispose(); - this.paethFilter?.Dispose(); - this.filterBuffer?.Dispose(); - - this.previousScanline = null; - this.currentScanline = null; - this.subFilter = null; - this.averageFilter = null; - this.paethFilter = null; - this.filterBuffer = null; - } - /// Collects a row of grayscale pixels. /// The pixel format. /// The image row span. @@ -859,7 +870,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image. /// The quantized pixel data. Can be null. /// The stream. - private void WriteDataChunks(ImageFrame pixels, IndexedImageFrame quantized, Stream stream) + private void WriteDataChunks(Image pixels, IndexedImageFrame quantized, Stream stream) where TPixel : unmanaged, IPixel { byte[] buffer; @@ -957,8 +968,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixels. /// The quantized pixels span. /// The deflate stream. - private void EncodePixels(ImageFrame pixels, IndexedImageFrame quantized, ZlibDeflateStream deflateStream) - where TPixel : unmanaged, IPixel + private void EncodePixels(Image pixels, IndexedImageFrame quantized, ZlibDeflateStream deflateStream) + where TPixel : unmanaged, IPixel { int bytesPerScanline = this.CalculateScanlineLength(this.width); int resultLength = bytesPerScanline + 1; @@ -981,7 +992,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The type of the pixel. /// The pixels. /// The deflate stream. - private void EncodeAdam7Pixels(ImageFrame pixels, ZlibDeflateStream deflateStream) + private void EncodeAdam7Pixels(Image pixels, ZlibDeflateStream deflateStream) where TPixel : unmanaged, IPixel { int width = pixels.Width; From 173659669e428f7c18c704c7ea50aeca5e2c93b5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 29 Apr 2020 22:38:43 +0200 Subject: [PATCH 188/213] use only netcoreapp3.1 --- src/ImageSharp/ImageSharp.csproj | 3 ++- tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 3 ++- .../ImageSharp.Tests.ProfilingSandbox.csproj | 3 ++- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index baf4a2ce19..185638d19a 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -10,7 +10,8 @@ $(packageversion) 0.0.1 - netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 + + netcoreapp3.1 true true diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index f380d0a6a9..101d279569 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -5,7 +5,8 @@ ImageSharp.Benchmarks Exe SixLabors.ImageSharp.Benchmarks - netcoreapp3.1;netcoreapp2.1;net472 + + netcoreapp3.1 false false diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index 7c80316930..f9e6c9da59 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -8,7 +8,8 @@ false SixLabors.ImageSharp.Tests.ProfilingSandbox win7-x64 - netcoreapp3.1;netcoreapp2.1;net472 + + netcoreapp3.1 SixLabors.ImageSharp.Tests.ProfilingSandbox.Program false diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index fdb280ca99..d5c8ef16ee 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,7 +2,8 @@ - netcoreapp3.1;netcoreapp2.1;net472 + + netcoreapp3.1 True True SixLabors.ImageSharp.Tests From c0494290e821fcb5201882eb7baa1d9ef34100ed Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 29 Apr 2020 23:45:58 +0200 Subject: [PATCH 189/213] add failing test for global quantization --- .../Formats/Gif/GifEncoderTests.cs | 25 ++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + .../Input/Gif/GlobalQuantizationTest.gif | Bin 0 -> 101868 bytes 3 files changed, 26 insertions(+) create mode 100644 tests/Images/Input/Gif/GlobalQuantizationTest.gif diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 588f652548..cbaed758dc 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.IO; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -132,6 +133,30 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } } + [Theory] + [WithFile(TestImages.Gif.GlobalQuantizationTest, PixelTypes.Rgba32)] + public void Encode_GlobalPalette_QuantizeMultipleFrames(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(); + + var encoder = new GifEncoder() + { + ColorTableMode = GifColorTableMode.Global + }; + + string testOutputFile = provider.Utility.SaveTestOutputFile( + image, + "gif", + encoder, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + + IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(testOutputFile); + using var encoded = Image.Load(testOutputFile, referenceDecoder); + ValidatorComparer.VerifySimilarity(image, encoded); + } + [Fact] public void NonMutatingEncodePreservesPaletteCount() { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 141a8d1c38..e18ef3eef5 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -396,6 +396,7 @@ namespace SixLabors.ImageSharp.Tests public const string Ratio4x1 = "Gif/base_4x1.gif"; public const string Ratio1x4 = "Gif/base_1x4.gif"; public const string LargeComment = "Gif/large_comment.gif"; + public const string GlobalQuantizationTest = "Gif/GlobalQuantizationTest.gif"; // Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite public const string ZeroSize = "Gif/image-zero-size.gif"; diff --git a/tests/Images/Input/Gif/GlobalQuantizationTest.gif b/tests/Images/Input/Gif/GlobalQuantizationTest.gif new file mode 100644 index 0000000000000000000000000000000000000000..b7da48aea1326842d8a4fe258cfd5528919e9113 GIT binary patch literal 101868 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%0DmmV0`M`U49E|_0Oa5R|6JU}H$%aO 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%0A-A2j{F#>DFadLMf5PCu6-a zr(s{DEqw*6bw}zU$0Q3zJi~Zrz?Ud_RW=4OkfccQX-GGr=qtacE3SYp+Zh9MXY|mz zsf?oDGz}1qCcUzl%!l9Ca*>|9G=1CN<~N~h0i6?wRCtb-{f){EUt!^`^0AA}EKE_k z_epn&l|b01UtW^O;AdyIL2KJbQdkJI*CO!y>{1BHEFa7WW%6A+QFuTVxL?E({*xN8 z5hdmIx%oTiy^MpOHY7XNFP8?0WJyIWn{GN{yM;zipq0CV9}#e*2g>mv{{0!P*xjiL zzsZ50FqU(frGqN zDTugF+Jrf&0*G3lPM8u7vm|(Q@iqVsXaFu|7ZJD5uQv;cr?G_$l6iTCG_MQZytejh z-a)(e=D`rl#P*LaZAIz;@3*!))B&5x$tdL99Dh5^d2`SgCK6#Bi<@%t?oJ0TJX~C4 z)y;S82PMeuO9(ic>|gi*=Om?cxrK9o@H_@k=DA(g_r(ec)WwE4xqsl#M44|@*l*}N zpfOpgNh3=gmchz%*zd9D9ZJ7Tr;Bw4q?2-put@V-f0c>+dTtf*Ng$46fx$r2!05sx z*Mac5E9ZS`JWYinZ)UmHCKCmV8PT!)Pn0wXf#jy&pTF54VQE%L_!qYsf{+e*r{2<_ z$$$m~4i+Mli!h6Wb_*e>V`Qo7+H9>!lSt};cCr>P6N5W+%D|L>a3)_SzZ zC_8N=iEOCOAIfTFfGTYRB#U!KxI980CnA%Im&oF?4RX9kl4x#i%xUbPq4>!#l3Ez9 z!ae0kZg#9v!KX^k!y z4Mj7qLvU(7j-xlnVIaGt!NMTn46Ry7DV67Q4v7nr$cDsjHkY$1QW=XObNgb4zz{T> zj~$z9wj|L+TEXVPT{JDufGWZDid}l9*DrDU^&tRk?$%7nhPR)}9|x-e66PCADA64N zHLn$u0rst_-N~tSM7Z_)-!>Zy?-^w>PET$be-^N(F|IO@RHQ*i!2h# zb2zCA4D+!Q$+$UWZcy`u9}*5nJ+jtqUQY-{ z7nlv=i`q-!<8QgxZWiC$oY(u>VhnquTDJ3`i23v*tUSMpvC+px^2l*C+9^Jv;?3)3y9dM(}F3JBNpsq78IRfxeXSzPJg0DQoDN+pZf@RI$NjvJ=we10_)J7fZ(1_kZAbw^~{*=eAod%R=J zOJfXEvrFYHrT`W{Wd-h>dzra>507KFwB><|h;-Ln%-}6fdGvI;8ILm84ehDc71fP~ z8`h6ab>77fHmM9wu=Ur0=Le34d#^_5^DXOD=gmaAoCAhv-;`C;1Hxsa#eb@6+54sH zdTp=z?OI$cvblS7JmLkARd2S%e~tPA_xe5gTV)6RhKmto9;rG&OwY)bMq z`LV03A<~!O*F|TzN6%twckjz(yByn)glVSFQ+Tw=m?XGgDRJS4=m<{p6gI-@CzFA1 zxZ})0^^#Ysne1@UnMDE0(QhT#s0)3h@dcC5Mhrh^?w^gY3YHqcWmrE}v|MJJ^X4qU z{Sk@1Y^vjwF7pX&edi{ve{q0Gs)ML%tEi@1s)=hV906j3Oa4*oR}>?brh^SvGo;RJu*xWi=|i^))q zY6EHBqCzb;n&hH#@6w^^&alfG+0F)Q?-ql})H*vnnD=W&U6Xgg9Ma5U!}T<;>8|qg z=AVR(*AdgjSG8^1*(s;%74g)DaPY|1<=*v;mD}@xfhI^vPNjS zWfwGoS+6?PyNC6!-`aUYhG>)BWWMQgRt3E9u^t@_r(ZE>?IdWBh+>ZeVc$k-NQI)i zm2v}7d^gr%8~wi#`nuL{my^@x!06qc*y{s9v$ezC*_-pd~i7HC?fd8kc=&??$}KVU+XolJgF+N%yGmDgt=M)#O-QZEl+T zXtaKf+7*78KOgrW739~ROyw+}*hFOD;b`JY0OpZzP%~-4U{=s~wHv!5u?^>>g@M_% zS19Im!YqDv@ZP1)#4W{coAWYS;&DOH!RMWk&xx=i(<3DH3+terLCVubslDi=BQK0H zDJsQ5v;Oh_c1U+mSrWzvuI6pk&vN&V%L-RMsIAi$UZ5hK=$U@JP+Ql-+__hqT%6lw z7VWZ3Y95DT6QyjFi*LBiT+58n9T!{#eBWbpnNH6?9sX~4;om&t^eKu7j5VpXhV?e` z`tnD@sp!qse&HUg%T*%Vz9!W?L;l8|*&U(yTtVMHWx#PCZ|Z}a!Ty8OWlQbi&za3>wg%>+6-Afnvy+QyzXzMEldYFM(yN`j-Z@3}fmii} z1L68sd$ylQU}LqUo3fxC#Md7uvJ>Uxm)fom4FBf3z(-!r+Azsaei)oZ`g21+~B6pbI*T#oi$L{-S?gSC;EmeBs4`#7*sh71&vFQ-;?}#tcUFxt9w%hMtjka&D;!TS! zH5RL|4xkdNsg%FJbx+btz;;BQjr*@#|Mg9pR#{&?#uhxzTpbxDHpBCm$tg!g6J9ns zFFL+#)ZUbRxqUpN`liske^vjGzxTJ1tE(lj9)ac-h<)X+eswtiEB)iYKl6L9l$Z!f zXK0q^+?H`k%n$GcH`a`>1EGJKQJ*x!#7bZ&FSP&5IAU8_2r8J{AoSYEhBdm|9HGW# z=>`?by=E;nLnX_Gfl|X??QbdX=fqzBgs1uH$!%hi&3Pf`X7I!f7W0Ts%m~VM^xERD|mJma5H zT#Kn~V^S*U6>c=MWN!(CEP*ZwAYOFsv#ko3?S2uYg5TtfH_1Gndcm(8b#&EVMU*+q zdh3{+MgS;?ygzi(*fl1SRbGB(w4|73ia@}&_u7|~6>{wtsfM&Jl6|>?-$ZGm(qc3$ zi-H+h!tShbBWv4R{hmNn#sQDkmBmml>d;y@={c!QJ*hdgdXIu~8JYZqq2cvGDlsn-h zvAvzp1qw^IXs%bSN5c^J*t#?sa3ba5dN@uXN791+lO0Mz7U}s%)_&u^%^6ME*$X8) z-eMsa0B58a@1cZo&vc>u0MEJFf`DJm{n#R9Ybw^vOb7uVN|+7@00<)}MQ%Z{yhTC5 zz7HC9-%@laXa_7xlHOnPS?|166f7DcfH*sg!?1KE4HY9Yys4%9^s4ii7_>Ce9jw2O zeoMll^Z`50*9geOA?Svb2Vm_99@%amOsG-W*GS9JQU(9Act8GCOWHrVzKSO8J%gcb zxbQn!YQY|4T^wZzyiC0JJA}mM9(UO&*a4v#Lbk|X*7o(5`#ZP*xE!- zzhu87Zp*MM1|TtS*yVt9&1H}UuB0V3!dHPM>G;8VVEy69wSzAsksEVT((tG3q7H3M zDMX0w|A}@aSt}u+0Vvo4I-Q^A>J!H7mm|mPO4e*|6>p7K>HBs@TdsqiWc4q)69<=Awg1^6`DDW$d9iD z2gDrvOiqYa(601ELIDh%zE!BCROx&XE;%2LrW8F7%N1;ae&76@gE2GPT-%T?gkRIZ zsjlP$PGwu8*i$EOXY_Q0-5n# z^{D|MM1H{4yHEU`}rc@T74+D^Qs5CozbWq`3Jryv6@*CA)+K z(f;(n+P-2{Q%hYC5Jiklp*@%E0(3x6X@fCKnR8cupq1PLlv)G}J#`+*n0#hg$uf~H z2gsAk-9zj^bOwXjawRdP>H4WZW*oV~^wyjYNXjar&4SMtylr@jK&@2X%KAdWP_tGl%1Ec>u{o+!Jn2Vnd z*JojN9q>X85;S#>3=Y^MvMmZWLt>U!y?HDPA0XXi)gTy9)@^QiTr+;fQ+M@dtGv^r zH`OL(#Hn-nNQQIKHJ+9eVFIqf$W1{<K>_woR(Qdy8$yvq$X9#7z0vbg#`;h{np}P!zWt-oHZ9? zdXs)bv=a-h4gMX(A(#fT-$U8e?@H@$ClwWNAVyMSoeq&(Zo?;~0k_>zd{oYpsB`+ zBS}u_ZfAk#EQyKjCNr3gKqfVyT}EOn>D7j5E95~AN{>!|B`BstmBo<+iV(=0De?Gn zOqc_p27HvI?i5v^I2ghAp)9opgB2@nTnc)aut5lIVeSk;jiLe@-bf0@rp7!kBfF$B zEJgxvl_!N4MkNbKj8U~VdSVhJsSh=l;Fj+GXN4P&R+}8!THdtto#~bVn^saWCRkQT zS+LJMDY4E9uPL+-!I?`_*3fFXR8fq%)ag@rzIy4K^&Z1n9?-K=)>X-@K%VR2Y(tMw zdt3qNs{sqZytW<-S+FS1(Inpqoo1T<8aqO}&Dverm(rg$vvi4)~7Ml0ay;W6@oJ7v>VS#+>QycfugSjx_A*rB_FcpJ|`h^DP-qc7yjbI z6EFXYX|af4CM)*^v%$^o!7g_Krs>DoVlamfLdLRY&4&N52nS&5_@^g*6;E~f9!I3% z578KiEiL^ZcCwN36q$Q63Iv{L5rp$X?OEP`PSRdtj86H03mMUaX@_Xm{>{p1*pC_v z#6HOMZ4cN`1xSO~lFc`@i)nBi@x2bR5muIy<;%YcSuKBIwZzSt0@VJCn`eVVX`}^d zs6aT?7`uwAT}edcT@LsmuyJx4WorX0QXRzOsq~_WR{XsgCspm#IF=PlDOsC1r$v9x zOwxVb3@?`H$9DF2;7~1uua5JPZOc`xbY z>C#dVVZVJ9`VSWT+?JJn&mU7=%>y{RtJ~LQ#&7${N7Pf(xqq> zxVix3{EJ7EkSwcWFUC*mNfbQ7EJ;vC{W$v6BAlkIbuw?#|Kl4Ad+SWd*K71a{&)Az z(-tHDn1Kl(JLJ3hWL~@=kfc^QxX>_YYWBOWB?^#)aX?g!JI z?3t?;TU%fHi4y}4fEbri!POQ&Zrt}u?HO+@Eq$y2`uOj`Nsh%nuQ?*TQl`Lg29c%` zPtpg6U6~QRZVOWL(1tQQL8a;5?#`n=d1)xgq|7p-OA*qj<4coIX^wPo6`={mvJ&oB zq(ETuA_)bCs5b}<6T6N#zqHV)a?4o}akljv`i5Zdq6pX&5q~*<)bSq%098(8aa--f z@ZEzbx_{)d!KJ@dC!?FWbHz^AXW9@@;*Et0n48|V4^eFl*ohx8iA37us{T1}2=$dl z?GvkXBMEBS1S++iCp}i1*)HMNrp%+-`wkP<&6=%=s2i#sf*gX*{`|aY`PQ(XNINbV{cDs~$%}z=<`1Zxo0jmx`{x>uEIQ_IZvH?w#QJ*uK=whhZL7rC^7uyY@Sq z`u%*O2$5p_r(O3IHbT?IGnlI?r>b_w$QlB4xq>G)>m zyElzreWuw-rAY0^??b#-KD%RfVyV$i-#4($kTolDB;Hf~()Mv_b3Wu*|H5^LNPoaA z`;Yer`ORNt%jZ2ofTOaP{p*!?P)M7R>>wk<8qLG0sui+!07U+9#Pu-CVG31d4BhFjWC@2+4*8l9h<_J>kMjn8P}W5UdbLDceWu3YcDFxObIe4n z-ba{NmZ6IYLG#6J_O{81Fp&0AGKi4{(f~cq==4&)5XRvB=1~l&iWJH=jEq7!Mhq(? zjtE^6kmXTPIdn85;HS66FlgqM`Tc=_Bv{@@JN(fG9S37W3yGJImPcRlPoyY*IK%ol zBWT}zHQes|JN~sb%2yS8?OZfq&hH@RRNYpZc$QSB+*7WXa=jW&HN6m;mPm$WIzydR z$DolY=iiRUya3B$qvRt-R!j3w&7rgV(TiFERgzXA0|642VNQ6lbp$*T9fH#vzKsf& zN5wI1x-MEg9#zu*bDeZes3Ev1AoB@*=V+lN?YIMG{gxIHjxtM`5fhy1cbPm`)xT5& zT5PVDVmp7vuHGrN5{0Ym^Y0r#bdl+jzpJ`h+hHhbFQBnzw&P2zGSSGJm=8s65`m&h zWQ)piMAzRuROT`h=GLWQH}vK-qyqF!$T;H+B^hcb`k#Ocs2S358^yq}k zo$dICeZww&yiI;@(Bw*y-T8<)^SfP+J#ZFmWaxt&T>sEjP@T|6a+*D;2A$VC5(E1_7>qlnnxETFWr* z_5g)$tLW_TQjGb)iWdxljIUqW7iAaazWT#*o1D07Pdz65jMF}fH|^{w^j|-9bh+C5oa^fC^d26UMZZVXoHCh zbqHWy0T@=U|2xSi>KB1wP%UjunZ-d%BaRMuXsO%$k&184Xj*(Gd{95 z;Rlo>do|tY7)0sG61HG8ff#;>#lu~4>uEe)^8U#bk+UJ1AB zKB%ZG3*eHJsIyi!HRBVmj9~m=g)RK8KQwB81yN960>sF5bmKCRrEs8bz#i^gJtxR4 zyuw_6*q7Cl0-HMuVr;S z{!KQ(=z(1pGsV}67%QFe6UU1*Rx!848P_1Hbgvi_V_PFx$S0?6wCS;#-r+n^V|yq+6Vjw0QgSI&Y2pzOW4xi@=wrI>heH zKRS^UH5oLhsAHS7*ge-a1hhU~cBU8;Uv#0qRiIa%*2?ch#9&QzR->7kmoahjf>PWFjpa1r#NgzD=E0KyS zTpq*cmV8tjTuF=3K&U#rBI0hUZ0LJA2q7P`aqg4d>7a9lGwo0_u=g&o!sefc4%r5M zO}Yu|+JOPB7Y=<#&*SpW1B`)V;i`r<&O>-5s@R{05=BRKO!{6+Y#NG$3nddhKOyKxDRGb?o~zWl-G| zFj9B(Tn_duBY0eI8|Z6eVZ^Cvn6QZ*G#JR|8ymN8XS5 zGLuqgZzD1+s9K>vJ&KmNfc4+pP2iZ)`huj?)U46sLH-nR!QvvQJ_QVOh;KJwU$S~J z*nC+oBVCdHZvpSWS;pR_5sJCHyv5PlsWFOf#MzloJAJQL`A+yW6HJNL;S^KSK_fq| zmL2lF7))0Pfg`Gz2Jhn+u}$ENB2BL^^Z&inuTImEzyK)mBa&*fCDYTk>|^X=GkdCr z9RDrhfV=CR*9t|twR-1;3&wf9*Zo{(%WLFOuGT+t%-Dk$n=Yt}E>|227O6yg>|I9P z{)2-gCly3sUM}l>CQE6v(+?CYT_*GYQdb>KOxgdA?qLj3?QG()Ei~uNFJtW3sI21` z%S+TRJnl?}f@gv$XLi^(u*7DnFzV9lSBm}{k?5JTcbSO~7_Hq^E)pH1zuGaTOkx#V zbEH^fa~YCPSh&R;jNIA8HQ9PlUPb6#?#f&;CZBjU4O$<_U--8;ixaeTY}`~_x03hL zCD${9$KL!aX!NVe4llnk>h3a1%H)>lJn-Lobi!C*{%UFBepT&cALV=^MQ;m5JxsN` zrF%)XqUf@64=dFNb*RU(-(wYAeHe3o?Nt&Zfp!>*?Tb~{!ncCU7q9C-SYMC*M;=EWX*6yg@&@9YY49JCm(c0r7f5|?hlC)vGw z8LsD$e?5rxQ{q>{-vTyr%~}yLmQ2;Vxy_bdXc& z%EY%~IS-NwoZdOlc8JYpsby3K#(jPPp#Q$S35o+CT(IuVQ=5*iUY_(}aWII@63>03 zRflFLZN|PBYN{U52X7b^F1MKUrf*;VM1k;|eQy#wFZ+9;+_MzbAU`QO(HXp0zcUk0 zb&apy`$DG^!*IUYcN$utwtqF`G_?NMj-o^fW{48 z!WvEdxZKTQ+|xtp_K*7iCReUmcAZb^dnS|XX3XXn1qzmzlE%~7hk->-Slmjk*jLDA z=P_Jss2W4|n8TsL5Axf)0m0rjm3_QuujIG#w0yXd#_?dN|9%jM$N7d=~5m8+z~tE!xfo*L)W zg(Ie-56J98R>==`1s2(wQUw)Wv$5P)G_HBp$8^r#!{PJ%KVfr5c z8~j5Ukj?ejyK~>c^{@5QYc}W8YcLogj5qCsIW7s-41E~legNHz%&Q-A&q$iT*`ZQ9 zX_%Q&K<_34KNL;ZlsNXXHf}+A<5xduus7AznU^d>31?BPzIk+nCIi_I;}w7%7;3^& z?pklpUd+FwMmFAGi&KSiWAY1{2D`e@ChkY>AFpuE7`TtWf;dFcBlhXPk&D7_@ z1T@c5^Tv+@d#zfhHM`B(Ji8Y4Av)M;31kHee@}1q7DH|LIh9$lkad(ny237gN~}PX zGBXAoZu3zyBI88SPJtinhRtHQepl($&P(!1Ncs5@KbnqlF^oSP>t30PPUzF>qy6VI zQOGDgNJnX4KqN7ufXc?-`DS2NaqEESZEig0K%V0 zd4;wK82Vz-eDX%Jce{)SLQwqz@6tyINhFdO;?@(lL3ZIb8Fy)yRx>NEpvh+)vVJEd zg&i@*@@OFIx*k1^TEMNlZU$Y0qCUCt8w|6+mC522i>8;Tu;*q0R+RcbSqW>0LVIC# zG=$CpwvJCu-vliU{SS!W(gG3+aQHawK}X9=;M^Onov)4$KJYMvF{7G89aTBwi3Bz; z(>&W~T+H6HzC(zYvgW_P`cStsk?q`l@gl?OVNN@jvCymGTtBV_l2TqWzFM6zE zC`8*-6Wi2S7YiLrN!~9~29eN0HmSoV#Wmyo`%JX#95+ubm2kP(;s`xWO?8zjeWb~7 zed+SGn263D7C85QAAkQR4mGlp-aPgb zAD+BX3?jZTC7SXd!6nW@QACpWjw|-J1*x&iFMn#A8<)ko88Kg>BQSG?a#{aVRMvXI8D(yz$G05@O6WuZJ#XX{Z=(*UCkQD_{Y z%E2yFQ@Yt)sGY!uDNM7wM5u~o7t79b;ryrjgKK1g6(R;v9Cpe9I~LA6^-8d=Nf+R1 zPwupBdVMN8=a|4eWN3e0@+30V@;6TD@(PaF_ciVDt{I6B?>1z&=SK|1q%QwC+*&~$ zmhTR%;?j7!S38MhvzM!$^wC<1?u5MDJAV3;lB3b^F~qycwrVm}FJS$t&-6N1Y@`tT zn~e0>fN_)4U3fYtGD&Z7HAnyZ^(1FK#^Zd$b|PS579#r^^ut0xLxE_}Dp_NziC5C{ zx2(aS8$!WTMu=^(4>8lSDM|$G9Z%=B9JV+KwrK0ZVdPYr3j&{+Xqq&hEdM4c z8U_~`km0~b)+ByxQQ`k0%f&c^Ny|QPgY2vnC|MrXXvCtWFr*reAn`#KQhoyVR|Hjmco6Xz6zIF`hV9mFxiNQMAQmzz4hI_HWx{!wUJ zUHwab_kG?CN@_DYhS%Zud4zN*GQ`r~L|EI}U)?t21b!Nr-IFM^)jGs|>}>*XWrPd?4aVbR z2Q;fFG+B6)+!JDrv`Na{@#3rF{meRXD3(W1TV3pB0)0a$^|HmV!kP$4pkEQLv}*qI z=8E2_Sxh%u#7Fj`wbl5mLg$aeO;3ZR#cD*0S=$CeF*!>G85mcvrl{~SYMIvHAPlqX zVTdoANX8#YrG@E($sKr$Kl*(6B$D(g%p(%(DIU00q4Ic7E@|R|X3cPX&qdaE1>S<3J8K^IH^rtuM?TB08{B_P-M< z>^4j)q?SuWe1v7bhByA&SJ^|h76eYaJOOx^A4w8VmrbK;i;DAOnA#)akr!)eq*`J&kb(xyj zgZ;{XzsFHj2PJ62ksT^4d3JViRNhp62w!VTiT`>BAQ&J6XB;bx-iBbUpm{H%ZQ7r0 zbM%JSB>fjebqK1>@rsExmex)jxoZ%4RBH~CUx=EXe$L*!$~Nt}E09LPPr+E2PESP2 zvdylUf?F$_?~0{m>dzox9 zRYy%Jn`)GlNG!8_WBl@kG9M^x_kDZN2T$mt1o_Ho1J*BecION{>_1@UVWP7r@~eEc z*oybX1{ADAG})iJUjeugI`a73llwMH*N>ofhu&X8Hgw^Dd=HRPEZDvL&)6 z5{ik#qzee2#5#-cn+U@)zl_H<#%0!3lk|_eJV(beI^Anlc>Vf|$5O2@*)2<&rh$y` zQ<4A^Fl#K~ZDDq9#B(veLwA%&m4WM8y~eL7^rY^r(&{{xi2M9AZ#u_Du2SSsH_=sh z!z;kOG3dWW@^?fdf}-%Tdy=0PiY`Cb+WOHq&eD3}Pgem^ zju>MOQDB`&uLq+UVlrxFBsR8QebT$vheQy>aFeM`okzEBQEtknk2CSj`(A7$MczwY zIR}5K5k5Ox^?%mN|9goT?%&&7>rt?g-dqWmTUX-SWkB}6Bn-d65y;FF=-B1k@=Q@f zz{^&~iDS5#COnmWBowhE$Tzb)GO0h9!VdCz7V22f?oO~nz~-b0MQ1k$;-Q7$Gk+BL zMKUC0hAYB0^lRduSALFG7M!|zl<~hg`|ZkqX-<&a@jeTtJ{`gv@#~&Uf zwH^|267o*>uUvVPkd@7?NJUygv6Jg^CQSo*)^O=?A=8=rgWcW6P7JdOANy zeq3GVp=kQ3EvTZcEqlU%-OmtO(DdP6Kf-*&_FmJc#FOsyjwUL^OM*7CozLKdg1n-x zIx{nYLW`o>J1vWgLc%iry~(gY@k!&n6T zbSfQRlf$rtKU2E+s$71E)`-Lfk2$7?`*kg`ju2XDHoN%&fHn`oIwi`G%GkVY5e!Wk zt!S-SUzY#UDdR>tM+9`me;HgH6YAUt%P#?DWXv$N-ScA%^D{mhXH(l{;2x*)b3y`+ ziA_N3%-`wU1EoGJjH5O&$DfdRInjsquaKe)D3EJ$=dU>ctnA-aFsBm(550jvoPY#~ z&yix%OpM{57PVhZS_CP8O9RzU7KvyM!GkBC-O^+-q-<=4C6x_QmFy%qT2&mq>5a1u z^9Pd_N?CeIG+jzVsSc2e%)O?686DY6{2C6>^oi_9lO@p9pst}#*YRFQ`Ba{nxJ<5ze(Lc)9QUIzg_J!TjWaUKHYbe9=EF=6AmlbIb@aQ;dA`lz}nkMTQ2#c(6T z?rVI`A z49Lps6E1pxbj}#Cug&?eQnGI|L~uit=WS(GfuW!jGkd)PP)dPzM9L3FIZiJbc@iq| zeQ{@V;M0g9p+g25j`XjUpg%~V=cDF7HvK#hlZzfKq>v-2mKjA`{XufFU~|Z;RhQOm zmk_b0IZ2udC|Bd2v}nC6=}!o%uBT4yX;?9VnjwKkj*S-ZFChPCD!YvYDlDjXB$Z?^ zV>1@gpHomcs0WBthd1ZA9+EHM1E)hFKO=Gx9JR0)R4hXoSpmqP5~Gtl!u^f zy-b1tFTC#oJXK!mlUqgsuc3k)$_>&M(Nw0#mV=a`6-JeBNr0kJ^{cAidyi%O|3=7% z@tqRl%CVp|hErv>Cneo~5le+LYn2Ozay2##E60qCwt^__|w%rYW+9cCxxZ@M3XzqY@m}mD^O2 zTYA3*;~S~)V{HU$Hr^|h^NO^P<+XmOZ936~l1M?pkk(fpN3CuB=oQlD)i{VLycx=Z zr%)TBFW6$_)IgR8J^tH7VO+i?)K-&Q!+x3ZKCc>L-1gw8A+!Y}vdO>z)VXvw@k~Sc z^PmLeb(OiecS1$9wH^M-Z6ePN4i~ThrAn+zKyWv0k6$}QcT==eUAceLwNWM6K`~~o zp=Vw-CRwAAf3t~E7x`4l({aa#uHx@o?IXGEd~9`mwVg_2&DGm2n8KNI-B}JsT8*{2 zT}B$g(;?(x-Hb*JijK{dxlQoPGExh8wNn9eK-G41RUlHRVQ$ZxCqCf3V*uXT{-dz4 zJ1NGfme9CmuMA!l4>#@Z@WrTGnW~VTu0E>mcnuCvZS!t%WvfHMsds(uQ&uUch2yRX z^?2sh^ec6wcUQ^yH~Ysy&Quyyw;Q_1;e`i{p=|x+C2(kMg-1Y@LmZTRs(&@E+-|jM z?YtvxWbm6~_pM54^mKQm3S8Wx!x36Jm{&tU-klNOk(Fl#1h?Ej52`|;2$RFY6m@X{ zr6TcV%J7c0xbh>mEwZ1A;^&9AZ zd%JH}3%nf;PmWsW!YbJs)XCdF?^M0k)Btdv;YLQ2Gcf?wz}_C~Zik)fE91II_9CIb zsg|}w12c{KmoT>Yo*ve2!jleMSP&68Ts&{Ay>4L7vDWeLa9eHl?R4{qYHQ%dRJG6; zcX#m-e4s;RuFI>g(75{@6gR57+IYJ&qjqXLupibVG==;A1NlUZamRE1aG7!48e1QG z9d!NgXc~C($Hf%IMMv|_cz)f0eO^1RSRJ}azq2w7k)vVXNdr56VW($7+ZXt|r!OLK z_?_Bfr%Eq&&(g?6hVFLfUcds{?$kcUQob+n9=*+uqO0w)}HP0E4@l%&!T2RrtDS()kD4hO%Fb3-Fr`oLXh;SanSAg2Pk`DuP8ykGHxG zrdoR^OLwbU-?10f3jj^8mpXeI64*L?dsgmuRz4yIFu)tvpIZf=TMdE+wuy`9{dzVH zr%5=*&1Y8vuRDO;P_f?0t~a+P*=T_U94~*qD!zX-enA*Cxy>5+A7om<87jOza%@t5 zDBbVh-MiL3Bo)|ZH4B#)nGa?I3hyj0Bn-oio4nCF*k&g<3x-p~X42}L_jXEx#rR-8 z1w7qN^Xx6yF4atN>m@;r#o#rTows##Rio1k_QH1N?#yj1<-gqaJ+j_-k>;uG#%avP zwBGFvvR#%Iz|+OXYqWAFiPLod%oeOb7HbODa@{IfH%bxIm7efzJ7I5TXJj9~7Ou8a zkhrpE+{;~m(D}E)+@v0~TNT_5KxFUy+tV#DJ%}__?8!cYhB0nQxmV}ZmZo;t`rPy7 zWh88;((%6*qPzpjhW$9v5i<2I<=yq5?!oqe$WNvdDc!?F4Q&{66QI5!%j*N`;BO5k z1oD%3;Ee`~xiK1womcqoL(RId^I}565N=NoR#I{Hc2AG&D%`jdx~mX@F+26QX}7+V z%d~$Yar<6){8qV3dbx)fb02QfSyz8ZLHcbkzTbrXY+L2b<{D;P`R#cYaN2WJ++FE} zdESfOlkK?px+`|XU9g>QqOu*1{BbWKiDT~6c|uG5J2;^f+xg_8r<~37n_=#8p1!jHElFPKz)x8%6zsYDp0?jp=6+_i4h6SG82A6Vb`;iMu$XA^ zdD+D_kwAC>s1lbq95*EtQ`Z-G!^MMMK%Jh1XE3UZdgIprQTzMmv-#hS z7TVyPrw*YYCNkamt%if%kB@8?b}+q*7du!y&d^!7Q0)~LY8cYFrB;h^lOjefNU`!R zeVWmG*0r0cEn2|1_B0!D+%JY86T|myI&+PTigfc3u`zm&L=>m0h=}Cx5M=XFIqPF| zVUZ>VHWC<-kPw7fg^&@?C+#mTQEnBK9;Sv~+}*?EhJ-*!fHE>lP~|5nVS$uk(GeuA z+%Dd`*6W6ah%h|5Hv&}zTO7%DH3j9(eH2~4DZ;?rLiqL*g`@M9&*A=CWO=0tY*m<9#v{h}whjJoC)q)v6KBz5agaXtK%h1-HIY z{Rz^Dke0w>Eq$q7<*%IK?FMd=+tRtz~M=3t8&Lf?S1bMxfhx7z{XzmCy#(dgVda-CPJXOlO=`R8Fb?QxUN$ z8Q)MdM0D{-ilxU#AzeH?z}>*QEiEA_*RNA=UOMGeEzbj-G-?$f&oukXgXMA^gJidm z%>R+fF4ffNP!KlSeinSS1{67?5zZGfZI_ z1*PXo?zw0I5`}Zq@_p4G&*-ps2+i45@=hjkORMA;!*hy$;cp($S zbXiJIj}=l9AHrv17o^OYF!cerQb4dS&AXTo*I$g;Wf{B!jxU>Q%a}McApn3kzzv8% z1Rl`T*NNgk6LCYLH765u;2*$DMgRaR&`jJ|5s*UU(#7)N_@`A4;2cTJBs#z#GAfc= zNEveH-wS~zvvf3|NNFqt(e~nkxe*9hs74OPQgME5+DO1VGF73-*@{6wp1Q0_H!}}~ zt>J~&^9RyB)4ZD~$*HY@{&RF~8wPc|az$df&3N2scgdC|tx3irCmCH}!ok*+?tX^L$8iZ z@&i}UV}J!3o6^l)BSO&X!4YgzS-M}@{0SuP+VoJ2e->7vr3oAmEYig&?FrKjG7Au< zCt?N`01;4oDM(r$!gOttb@i1%(>!KC!T5&UaN32)(WgycW!ZO1X%v>0Vs_Jnciuq+ z6W(1Z0uD`62v;iPu!pz zeJ9YetqDK?>7#C^d%YB8k5W4ledl$tz>FSnfWkPo1zR8ih&g6Ewy{l$ z2GGFbvCvexLmt{j$bu5Wu0Ja@oj{0ZfeVDsPC=64-Ds!+3E+%B?h{x~R@f~Y*q~7m z2%-6ir~();h<__lQWKMa0}cjIgj7U<6_bF%|EZyfN@j|I7YjGUFq!}cX=2$lf}kPf z@MHj5Fogi!=!*xaPmWVd4!0nH5+vB^i&NwyTt;V_Fsvpuhr=Tf($H*G{Lcu zz$EVlX;~>z-M|`XNqfXBlZzY$C%ZGd#w7uY1tcU34=F4M$qXaHLFEDvAP1uWZdqm` zUH~L8%>OZpmf>(*=ejr|RFWVb+EdbEf=N6_4RZoxo9GROp_lTt|F4oOoCFS;s1A$9#bfd5RsfkOq=(kVG$4{A z6HRKw*+54J@j23;!WANxjTDkfq3H!RWTZ)6t$PsoQxaPWBB7G5G`A|=Lha-|rO=>y z-Y_W)7AhVzyv$%hy8r~NdOWOx&Y8t|>NGYHPw_qKom?bax4jOzDVtc7aJn zz)!**u1Sj$8q=lZ5iz(x1R`(&1>nONw>9Ynj53y#K7t04;;#b!LIDMAcbsuqk5UYD zFi5o5Tnxx?LIks5|AG<12SC=(wv!T`#UKL4(Qt-Wykb;1&A;${WCboe0S5#_NXUpB zBx1s14cpiO8Wzkv1VCX^Ft!TYum{J0Fp5e58ORJUPC^8b5C#yL$}y=j8j^728b_%i z|EhqEiJTB9Ke^0f7J!D;oMCBn`3K}}Fe?-=nPK2#!9Kn+m8opw1wR?jDF#B9tqfl} z|2V@$?gl=vOk_IydCCHy|8q>Z5#<#>pv&7B2A%l~EZ_RhKrXeU5q%FR$As5D zUU8LaZRZ9Xn${gIbFC|_vtMTz+F8yrnj`HEPiMK*Pmc7RrM>PagZsy2CbPQBeQGkN z`_2lev;#D4W?oB~)Kku|e`n$VDVw^?Rwl|-%>|i@5o6Rh~wSN~riiVq-&b%hY ztz~}dTN?w?#z`@?{~MfP;|x6Ckv=j8e7xyAtGVI_k93baPV9VFdf*hGxYXm#>39QK z*!RG8l>Lb4ZF3y#Vn6bgrwwwD7sJ%0Zo1w_z4iyFoB|0^fYdqs>qz&R(f82xu`izD z2Xwvf+<3I$<-YU7+t}eYzI)(jUFj$vd*P7Kxx**V*o73k(VtKD-6;|x*ce>b1vvzB_FzTxO*U*6&g z=e+N&%y_oP9LUlixG@&2YuVQX@Mkx*(%H`9*y|kpM;0UJIc80fN*QR2w7kf&_08&>2B{Bob#)1imWqL<~GPq(jxF1=7 z8>dErKE`+$$aWVPWm1O#^+X4hf^n_pY|dta?U#WZ*Myvv1F2O52&jG2)_+@NPb&R1% zE|u7316c~%kQoUy3%BPuwfO!3O2Ts zhClf?jME+WR6M5QC>{f3N?;a5W;8R#Ywwj5Au<*8#6Y@83nD2P+h7XwaF)1rV>2Q< zk423bNr|A55JnRWM0OK`k&YJ-J5}-?^wc>(kSCIXAsnM};9;0g5sqg9AZ8LgFaivM kA($L<3SF0u2XGQal9~0CndyL(o=F+U&|#=h0U-bYJC3yJPyhe` literal 0 HcmV?d00001 From 3e2f7dd310bf104d26746ecb5a92db752d0fb714 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 30 Apr 2020 03:01:34 +0200 Subject: [PATCH 190/213] BufferArea -> BufferRegion, introduce PixelSamplingStrategy --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 4 +- src/ImageSharp/Formats/Gif/GifEncoder.cs | 2 + .../Formats/Gif/IGifEncoderOptions.cs | 3 + .../Jpeg/Components/Block8x8F.ScaledCopyTo.cs | 6 +- src/ImageSharp/Image{TPixel}.cs | 12 +++ src/ImageSharp/Memory/Buffer2DExtensions.cs | 26 ++--- .../{BufferArea{T}.cs => BufferRegion{T}.cs} | 92 +++++++++-------- .../DefaultPixelSamplingStrategy.cs | 90 +++++++++++++++++ .../ExtensivePixelSamplingStrategy.cs | 25 +++++ .../Quantization/IPixelSamplingStrategy.cs | 24 +++++ .../Resize/ResizeProcessor{TPixel}.cs | 4 +- .../Transforms/Resize/ResizeWorker.cs | 4 +- .../BlockOperations/Block8x8F_CopyTo2x2.cs | 28 +++--- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 10 +- .../Memory/BufferAreaTests.cs | 32 +++--- .../PixelSamplingStrategyTests.cs | 99 +++++++++++++++++++ 16 files changed, 362 insertions(+), 99 deletions(-) rename src/ImageSharp/Memory/{BufferArea{T}.cs => BufferRegion{T}.cs} (65%) create mode 100644 src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs create mode 100644 src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs create mode 100644 src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs create mode 100644 tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index e0d8b3cd96..ba94851f8e 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -543,8 +543,8 @@ namespace SixLabors.ImageSharp.Formats.Gif return; } - BufferArea pixelArea = frame.PixelBuffer.GetArea(this.restoreArea.Value); - pixelArea.Clear(); + BufferRegion pixelRegion = frame.PixelBuffer.GetRegion(this.restoreArea.Value); + pixelRegion.Clear(); this.restoreArea = null; } diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index 53c4c6f3fd..aa276cd986 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -25,6 +25,8 @@ namespace SixLabors.ImageSharp.Formats.Gif ///
public GifColorTableMode? ColorTableMode { get; set; } + internal IPixelSamplingStrategy GlobalPixelSamplingStrategy { get; set; } + /// public void Encode(Image image, Stream stream) where TPixel : unmanaged, IPixel diff --git a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs index 5936d30cba..752e6866fe 100644 --- a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Collections.Generic; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Formats.Gif diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs index 064ca75539..2fbc817079 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs @@ -15,10 +15,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical scale factors. ///
[MethodImpl(InliningOptions.ShortMethod)] - public void ScaledCopyTo(in BufferArea area, int horizontalScale, int verticalScale) + public void ScaledCopyTo(in BufferRegion region, int horizontalScale, int verticalScale) { - ref float areaOrigin = ref area.GetReferenceToOrigin(); - this.ScaledCopyTo(ref areaOrigin, area.Stride, horizontalScale, verticalScale); + ref float areaOrigin = ref region.GetReferenceToOrigin(); + this.ScaledCopyTo(ref areaOrigin, region.Stride, horizontalScale, verticalScale); } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index f6173db972..2ab4728532 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -48,6 +48,18 @@ namespace SixLabors.ImageSharp { } + /// + /// Initializes a new instance of the class + /// with the height and the width of the image. + /// + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The color to initialize the pixels with. + public Image(int width, int height, TPixel backgroundColor) + : this(Configuration.Default, width, height, backgroundColor, new ImageMetadata()) + { + } + /// /// Initializes a new instance of the class /// with the height and the width of the image. diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index fea44f52c1..d61ac9087a 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -80,29 +80,29 @@ namespace SixLabors.ImageSharp.Memory } /// - /// Return a to the subarea represented by 'rectangle' + /// Return a to the subarea represented by 'rectangle' /// /// The element type /// The /// The rectangle subarea - /// The - internal static BufferArea GetArea(this Buffer2D buffer, in Rectangle rectangle) - where T : struct => - new BufferArea(buffer, rectangle); + /// The + internal static BufferRegion GetRegion(this Buffer2D buffer, in Rectangle rectangle) + where T : unmanaged => + new BufferRegion(buffer, rectangle); - internal static BufferArea GetArea(this Buffer2D buffer, int x, int y, int width, int height) - where T : struct => - new BufferArea(buffer, new Rectangle(x, y, width, height)); + internal static BufferRegion GetRegion(this Buffer2D buffer, int x, int y, int width, int height) + where T : unmanaged => + new BufferRegion(buffer, new Rectangle(x, y, width, height)); /// - /// Return a to the whole area of 'buffer' + /// Return a to the whole area of 'buffer' /// /// The element type /// The - /// The - internal static BufferArea GetArea(this Buffer2D buffer) - where T : struct => - new BufferArea(buffer); + /// The + internal static BufferRegion GetRegion(this Buffer2D buffer) + where T : unmanaged => + new BufferRegion(buffer); /// /// Returns the size of the buffer. diff --git a/src/ImageSharp/Memory/BufferArea{T}.cs b/src/ImageSharp/Memory/BufferRegion{T}.cs similarity index 65% rename from src/ImageSharp/Memory/BufferArea{T}.cs rename to src/ImageSharp/Memory/BufferRegion{T}.cs index 076f7f37ce..901c3217ba 100644 --- a/src/ImageSharp/Memory/BufferArea{T}.cs +++ b/src/ImageSharp/Memory/BufferRegion{T}.cs @@ -6,45 +6,48 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory { /// - /// Represents a rectangular area inside a 2D memory buffer (). - /// This type is kind-of 2D Span, but it can live on heap. + /// Represents a rectangular region inside a 2D memory buffer (). /// /// The element type. - internal readonly struct BufferArea - where T : struct + public readonly struct BufferRegion + where T : unmanaged { /// - /// The rectangle specifying the boundaries of the area in . + /// Initializes a new instance of the struct. /// - public readonly Rectangle Rectangle; - + /// The . + /// The defining a rectangular area within the buffer. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BufferArea(Buffer2D destinationBuffer, Rectangle rectangle) + public BufferRegion(Buffer2D buffer, Rectangle rectangle) { DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle)); DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle)); - DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, destinationBuffer.Width, nameof(rectangle)); - DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, destinationBuffer.Height, nameof(rectangle)); + DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, buffer.Width, nameof(rectangle)); + DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, buffer.Height, nameof(rectangle)); - this.DestinationBuffer = destinationBuffer; + this.Buffer = buffer; this.Rectangle = rectangle; } + /// + /// Initializes a new instance of the struct. + /// + /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BufferArea(Buffer2D destinationBuffer) - : this(destinationBuffer, destinationBuffer.FullRectangle()) + public BufferRegion(Buffer2D buffer) + : this(buffer, buffer.FullRectangle()) { } /// - /// Gets the being pointed by this instance. + /// Gets the rectangle specifying the boundaries of the area in . /// - public Buffer2D DestinationBuffer { get; } + public Rectangle Rectangle { get; } /// - /// Gets the size of the area. + /// Gets the being pointed by this instance. /// - public Size Size => this.Rectangle.Size; + public Buffer2D Buffer { get; } /// /// Gets the width @@ -57,14 +60,19 @@ namespace SixLabors.ImageSharp.Memory public int Height => this.Rectangle.Height; /// - /// Gets the pixel stride which is equal to the width of . + /// Gets the pixel stride which is equal to the width of . /// - public int Stride => this.DestinationBuffer.Width; + public int Stride => this.Buffer.Width; /// - /// Gets a value indicating whether the area refers to the entire + /// Gets the size of the area. /// - public bool IsFullBufferArea => this.Size == this.DestinationBuffer.Size(); + internal Size Size => this.Rectangle.Size; + + /// + /// Gets a value indicating whether the area refers to the entire + /// + internal bool IsFullBufferArea => this.Size == this.Buffer.Size(); /// /// Gets or sets a value at the given index. @@ -72,19 +80,7 @@ namespace SixLabors.ImageSharp.Memory /// The position inside a row /// The row index /// The reference to the value - public ref T this[int x, int y] => ref this.DestinationBuffer[x + this.Rectangle.X, y + this.Rectangle.Y]; - - /// - /// Gets a reference to the [0,0] element. - /// - /// The reference to the [0,0] element - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T GetReferenceToOrigin() - { - int y = this.Rectangle.Y; - int x = this.Rectangle.X; - return ref this.DestinationBuffer.GetRowSpan(y)[x]; - } + internal ref T this[int x, int y] => ref this.Buffer[x + this.Rectangle.X, y + this.Rectangle.Y]; /// /// Gets a span to row 'y' inside this area. @@ -98,11 +94,11 @@ namespace SixLabors.ImageSharp.Memory int xx = this.Rectangle.X; int width = this.Rectangle.Width; - return this.DestinationBuffer.GetRowSpan(yy).Slice(xx, width); + return this.Buffer.GetRowSpan(yy).Slice(xx, width); } /// - /// Returns a sub-area as . (Similar to .) + /// Returns a sub-area as . (Similar to .) /// /// The x index at the subarea origin. /// The y index at the subarea origin. @@ -110,19 +106,19 @@ namespace SixLabors.ImageSharp.Memory /// The desired height of the subarea. /// The subarea [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BufferArea GetSubArea(int x, int y, int width, int height) + public BufferRegion GetSubArea(int x, int y, int width, int height) { var rectangle = new Rectangle(x, y, width, height); return this.GetSubArea(rectangle); } /// - /// Returns a sub-area as . (Similar to .) + /// Returns a sub-area as . (Similar to .) /// /// The specifying the boundaries of the subarea /// The subarea [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BufferArea GetSubArea(Rectangle rectangle) + public BufferRegion GetSubArea(Rectangle rectangle) { DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle)); DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle)); @@ -130,15 +126,27 @@ namespace SixLabors.ImageSharp.Memory int x = this.Rectangle.X + rectangle.X; int y = this.Rectangle.Y + rectangle.Y; rectangle = new Rectangle(x, y, rectangle.Width, rectangle.Height); - return new BufferArea(this.DestinationBuffer, rectangle); + return new BufferRegion(this.Buffer, rectangle); + } + + /// + /// Gets a reference to the [0,0] element. + /// + /// The reference to the [0,0] element + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ref T GetReferenceToOrigin() + { + int y = this.Rectangle.Y; + int x = this.Rectangle.X; + return ref this.Buffer.GetRowSpan(y)[x]; } - public void Clear() + internal void Clear() { // Optimization for when the size of the area is the same as the buffer size. if (this.IsFullBufferArea) { - this.DestinationBuffer.FastMemoryGroup.Clear(); + this.Buffer.FastMemoryGroup.Clear(); return; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs new file mode 100644 index 0000000000..6653259c57 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs @@ -0,0 +1,90 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A pixel sampling strategy that enumerates a limited amount of rows from different frames, + /// if the total number of pixels is over a threshold. + /// + public class DefaultPixelSamplingStrategy : IPixelSamplingStrategy + { + // TODO: This value shall be determined by benchmarking. + // (Maximum quality while decoding time is still tolerable.) + private const int DefaultMaximumPixels = 8192 * 8192; + + /// + /// Initializes a new instance of the class. + /// + public DefaultPixelSamplingStrategy() + : this(DefaultMaximumPixels) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The maximum number of pixels to process. + public DefaultPixelSamplingStrategy(int maximumPixels) + { + Guard.MustBeGreaterThan(maximumPixels, 0, nameof(maximumPixels)); + this.MaximumPixels = maximumPixels; + } + + /// + /// Gets the maximum number of pixels to process. (The threshold.) + /// + public long MaximumPixels { get; } + + /// + public IEnumerable> EnumeratePixelRegions(Image image) + where TPixel : unmanaged, IPixel + { + long maximumPixels = Math.Min(MaximumPixels, (long)image.Width * image.Height * image.Frames.Count); + long maxNumberOfRows = maximumPixels / image.Width; + long totalNumberOfRows = (long)image.Height * image.Frames.Count; + + if (totalNumberOfRows <= maxNumberOfRows) + { + // Enumerate all pixels + foreach (ImageFrame frame in image.Frames) + { + yield return frame.PixelBuffer.GetRegion(); + } + } + else + { + double r = maxNumberOfRows / (double)totalNumberOfRows; + + r = Math.Round(r, 1); // Use a rough approximation to make sure we don't leave out large contiguous regions: + r = Math.Max(0.1, r); // always visit at least 10% of the image + + var ratio = new Rational(r); + + int denom = (int)ratio.Denominator; + int num = (int)ratio.Numerator; + + for (int pos = 0; pos < totalNumberOfRows; pos++) + { + int subPos = pos % denom; + if (subPos < num) + { + yield return GetRow(pos); + } + } + + BufferRegion GetRow(int pos) + { + int frameIdx = pos / image.Height; + int y = pos % image.Height; + return image.Frames[frameIdx].PixelBuffer.GetRegion(0, y, image.Width, 1); + } + } + } + } +} diff --git a/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs new file mode 100644 index 0000000000..e2774850a0 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs @@ -0,0 +1,25 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A pixel sampling strategy that enumerates all pixels. + /// + public class ExtensivePixelSamplingStrategy : IPixelSamplingStrategy + { + /// + public IEnumerable> EnumeratePixelRegions(Image image) + where TPixel : unmanaged, IPixel + { + foreach (ImageFrame frame in image.Frames) + { + yield return frame.PixelBuffer.GetRegion(); + } + } + } +} diff --git a/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs new file mode 100644 index 0000000000..71b20174db --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// Provides an abstraction to enumerate pixel regions within a multi-framed . + /// + public interface IPixelSamplingStrategy + { + /// + /// Enumerates pixel regions within the image as . + /// + /// The image. + /// The pixel type. + /// An enumeration of pixel regions. + IEnumerable> EnumeratePixelRegions(Image image) + where TPixel : unmanaged, IPixel; + } +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 6eafbda891..630c88bac7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -172,13 +172,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms PixelConversionModifiers conversionModifiers = PixelConversionModifiers.Premultiply.ApplyCompanding(compand); - BufferArea sourceArea = source.PixelBuffer.GetArea(sourceRectangle); + BufferRegion sourceRegion = source.PixelBuffer.GetRegion(sourceRectangle); // To reintroduce parallel processing, we would launch multiple workers // for different row intervals of the image. using (var worker = new ResizeWorker( configuration, - sourceArea, + sourceRegion, conversionModifiers, horizontalKernelMap, verticalKernelMap, diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs index 898809d5a5..6cdb7934c0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ResizeKernelMap horizontalKernelMap; - private readonly BufferArea source; + private readonly BufferRegion source; private readonly Rectangle sourceRectangle; @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public ResizeWorker( Configuration configuration, - BufferArea source, + BufferRegion source, PixelConversionModifiers conversionModifiers, ResizeKernelMap horizontalKernelMap, ResizeKernelMap verticalKernelMap, diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs index 76068ab432..0237c81705 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -18,20 +18,20 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations private Buffer2D buffer; - private BufferArea destArea; + private BufferRegion destRegion; [GlobalSetup] public void Setup() { this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); - this.destArea = this.buffer.GetArea(200, 100, 128, 128); + this.destRegion = this.buffer.GetRegion(200, 100, 128, 128); } [Benchmark(Baseline = true)] public void Original() { - ref float destBase = ref this.destArea.GetReferenceToOrigin(); - int destStride = this.destArea.Stride; + ref float destBase = ref this.destRegion.GetReferenceToOrigin(); + int destStride = this.destRegion.Stride; ref Block8x8F src = ref this.block; @@ -92,8 +92,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations [Benchmark] public void Original_V2() { - ref float destBase = ref this.destArea.GetReferenceToOrigin(); - int destStride = this.destArea.Stride; + ref float destBase = ref this.destRegion.GetReferenceToOrigin(); + int destStride = this.destRegion.Stride; ref Block8x8F src = ref this.block; @@ -160,8 +160,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations [Benchmark] public void UseVector2() { - ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); - int destStride = this.destArea.Stride / 2; + ref Vector2 destBase = ref Unsafe.As(ref this.destRegion.GetReferenceToOrigin()); + int destStride = this.destRegion.Stride / 2; ref Block8x8F src = ref this.block; @@ -220,8 +220,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations [Benchmark] public void UseVector4() { - ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); - int destStride = this.destArea.Stride / 2; + ref Vector2 destBase = ref Unsafe.As(ref this.destRegion.GetReferenceToOrigin()); + int destStride = this.destRegion.Stride / 2; ref Block8x8F src = ref this.block; @@ -280,8 +280,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations [Benchmark] public void UseVector4_SafeRightCorner() { - ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); - int destStride = this.destArea.Stride / 2; + ref Vector2 destBase = ref Unsafe.As(ref this.destRegion.GetReferenceToOrigin()); + int destStride = this.destRegion.Stride / 2; ref Block8x8F src = ref this.block; @@ -338,8 +338,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations [Benchmark] public void UseVector4_V2() { - ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); - int destStride = this.destArea.Stride / 2; + ref Vector2 destBase = ref Unsafe.As(ref this.destRegion.GetReferenceToOrigin()); + int destStride = this.destRegion.Stride / 2; ref Block8x8F src = ref this.block; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index f55e46c3dc..169b9c0fcd 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -43,8 +43,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20, AllocationOptions.Clean)) { - BufferArea area = buffer.GetArea(5, 10, 8, 8); - block.Copy1x1Scale(ref area.GetReferenceToOrigin(), area.Stride); + BufferRegion region = buffer.GetRegion(5, 10, 8, 8); + block.Copy1x1Scale(ref region.GetReferenceToOrigin(), region.Stride); Assert.Equal(block[0, 0], buffer[5, 10]); Assert.Equal(block[1, 0], buffer[6, 10]); @@ -71,8 +71,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100, AllocationOptions.Clean)) { - BufferArea area = buffer.GetArea(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); - block.ScaledCopyTo(area, horizontalFactor, verticalFactor); + BufferRegion region = buffer.GetRegion(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); + block.ScaledCopyTo(region, horizontalFactor, verticalFactor); for (int y = 0; y < 8 * verticalFactor; y++) { @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg int xx = x / horizontalFactor; float expected = block[xx, yy]; - float actual = area[x, y]; + float actual = region[x, y]; Assert.Equal(expected, actual); } diff --git a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs index 77e899a4c2..81173b456e 100644 --- a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs +++ b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs @@ -16,9 +16,9 @@ namespace SixLabors.ImageSharp.Tests.Memory { using Buffer2D buffer = this.memoryAllocator.Allocate2D(10, 20); var rectangle = new Rectangle(3, 2, 5, 6); - var area = new BufferArea(buffer, rectangle); + var area = new BufferRegion(buffer, rectangle); - Assert.Equal(buffer, area.DestinationBuffer); + Assert.Equal(buffer, area.Buffer); Assert.Equal(rectangle, area.Rectangle); } @@ -47,9 +47,9 @@ namespace SixLabors.ImageSharp.Tests.Memory using Buffer2D buffer = this.CreateTestBuffer(20, 30); var r = new Rectangle(rx, ry, 5, 6); - BufferArea area = buffer.GetArea(r); + BufferRegion region = buffer.GetRegion(r); - int value = area[x, y]; + int value = region[x, y]; int expected = ((ry + y) * 100) + rx + x; Assert.Equal(expected, value); } @@ -66,9 +66,9 @@ namespace SixLabors.ImageSharp.Tests.Memory using Buffer2D buffer = this.CreateTestBuffer(20, 30); var r = new Rectangle(rx, ry, w, h); - BufferArea area = buffer.GetArea(r); + BufferRegion region = buffer.GetRegion(r); - Span span = area.GetRowSpan(y); + Span span = region.GetRowSpan(y); Assert.Equal(w, span.Length); @@ -85,13 +85,13 @@ namespace SixLabors.ImageSharp.Tests.Memory public void GetSubArea() { using Buffer2D buffer = this.CreateTestBuffer(20, 30); - BufferArea area0 = buffer.GetArea(6, 8, 10, 10); + BufferRegion area0 = buffer.GetRegion(6, 8, 10, 10); - BufferArea area1 = area0.GetSubArea(4, 4, 5, 5); + BufferRegion area1 = area0.GetSubArea(4, 4, 5, 5); var expectedRect = new Rectangle(10, 12, 5, 5); - Assert.Equal(buffer, area1.DestinationBuffer); + Assert.Equal(buffer, area1.Buffer); Assert.Equal(expectedRect, area1.Rectangle); int value00 = (12 * 100) + 10; @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Tests.Memory this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity; using Buffer2D buffer = this.CreateTestBuffer(20, 30); - BufferArea area0 = buffer.GetArea(6, 8, 10, 10); + BufferRegion area0 = buffer.GetRegion(6, 8, 10, 10); ref int r = ref area0.GetReferenceToOrigin(); @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Tests.Memory using Buffer2D buffer = this.CreateTestBuffer(22, 13); var emptyRow = new int[22]; - buffer.GetArea().Clear(); + buffer.GetRegion().Clear(); for (int y = 0; y < 13; y++) { @@ -140,8 +140,8 @@ namespace SixLabors.ImageSharp.Tests.Memory this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity; using Buffer2D buffer = this.CreateTestBuffer(20, 30); - BufferArea area = buffer.GetArea(5, 5, 10, 10); - area.Clear(); + BufferRegion region = buffer.GetRegion(5, 5, 10, 10); + region.Clear(); Assert.NotEqual(0, buffer[4, 4]); Assert.NotEqual(0, buffer[15, 15]); @@ -149,10 +149,10 @@ namespace SixLabors.ImageSharp.Tests.Memory Assert.Equal(0, buffer[5, 5]); Assert.Equal(0, buffer[14, 14]); - for (int y = area.Rectangle.Y; y < area.Rectangle.Bottom; y++) + for (int y = region.Rectangle.Y; y < region.Rectangle.Bottom; y++) { - Span span = buffer.GetRowSpan(y).Slice(area.Rectangle.X, area.Width); - Assert.True(span.SequenceEqual(new int[area.Width])); + Span span = buffer.GetRowSpan(y).Slice(region.Rectangle.X, region.Width); + Assert.True(span.SequenceEqual(new int[region.Width])); } } } diff --git a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs new file mode 100644 index 0000000000..0787b56a9c --- /dev/null +++ b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs @@ -0,0 +1,99 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Quantization +{ + public class PixelSamplingStrategyTests + { + public static readonly TheoryData DefaultPixelSamplingStrategy_Data = new TheoryData() + { + { 100, 100, 1, 10000 }, + { 100, 100, 1, 5000 }, + { 100, 100, 10, 50000 }, + { 99, 100, 11, 30000 }, + { 97, 99, 11, 80000 }, + { 99, 100, 11, 20000 }, + { 99, 501, 20, 100000 }, + { 97, 500, 20, 10000 }, + { 103, 501, 20, 1000 }, + }; + + [Fact] + public void ExtensivePixelSamplingStrategy_EnumeratesAll() + { + using Image image = CreateTestImage(100, 100, 100); + var strategy = new ExtensivePixelSamplingStrategy(); + + foreach (BufferRegion region in strategy.EnumeratePixelRegions(image)) + { + PaintWhite(region); + } + + using Image expected = CreateTestImage(100, 100, 100, true); + + ImageComparer.Exact.VerifySimilarity(expected, image); + } + + [Theory] + [WithBlankImages(nameof(DefaultPixelSamplingStrategy_Data), 1, 1, PixelTypes.L8)] + public void DefaultPixelSamplingStrategy_IsFair(TestImageProvider dummyProvider, int width, int height, int noOfFrames, int maximumNumberOfPixels) + { + using Image image = CreateTestImage(width, height, noOfFrames); + + var strategy = new DefaultPixelSamplingStrategy(maximumNumberOfPixels); + + long visitedPixels = 0; + foreach (BufferRegion region in strategy.EnumeratePixelRegions(image)) + { + PaintWhite(region); + visitedPixels += region.Width * region.Height; + } + + image.DebugSaveMultiFrame( + dummyProvider, + $"W{width}_H{height}_noOfFrames_{noOfFrames}_maximumNumberOfPixels_{maximumNumberOfPixels}", + appendPixelTypeToFileName: false); + + int maximumPixels = image.Width * image.Height * image.Frames.Count / 10; + maximumPixels = Math.Max(maximumPixels, (int)strategy.MaximumPixels); + + // allow some inaccuracy: + double visitRatio = visitedPixels / (double)maximumPixels; + Assert.True(visitRatio <= 1.1, $"{visitedPixels}>{maximumPixels}"); + } + + static void PaintWhite(BufferRegion region) + { + var white = new L8(255); + for (int y = 0; y < region.Height; y++) + { + region.GetRowSpan(y).Fill(white); + } + } + + private Image CreateTestImage(int width, int height, int noOfFrames, bool paintWhite = false) + { + L8 bg = paintWhite ? new L8(255) : default; + var image = new Image(width, height, bg); + + for (int i = 1; i < noOfFrames; i++) + { + ImageFrame f = image.Frames.CreateFrame(); + if (paintWhite) + { + f.PixelBuffer.MemoryGroup.Fill(bg); + } + } + + return image; + } + } +} From b6208b9b61728ddad482efdd77b655ab9f03b440 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 30 Apr 2020 03:11:11 +0200 Subject: [PATCH 191/213] FrameQuantizer -> Quantizer --- src/ImageSharp/Advanced/AotCompilerTools.cs | 6 +++--- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 8 ++++---- .../Formats/Png/PngEncoderOptionsHelpers.cs | 2 +- .../Processors/Dithering/ErrorDither.cs | 2 +- .../Processing/Processors/Dithering/IDither.cs | 2 +- .../Processors/Dithering/OrderedDither.cs | 4 ++-- .../Quantization/FrameQuantizerUtilities.cs | 13 +++++++------ .../Quantization/IFrameQuantizer{TPixel}.cs | 12 ++++++------ .../Processors/Quantization/IQuantizer.cs | 8 ++++---- .../Processors/Quantization/OctreeQuantizer.cs | 8 ++++---- ...izer{TPixel}.cs => OctreeQuantizer{TPixel}.cs} | 12 +++++++----- .../Processors/Quantization/PaletteQuantizer.cs | 8 ++++---- ...zer{TPixel}.cs => PaletteQuantizer{TPixel}.cs} | 9 +++++---- .../Quantization/QuantizeProcessor{TPixel}.cs | 2 +- .../Processors/Quantization/WuQuantizer.cs | 8 ++++---- ...uantizer{TPixel}.cs => WuQuantizer{TPixel}.cs} | 15 +++++++++------ .../Quantization/OctreeQuantizerTests.cs | 6 +++--- .../Quantization/PaletteQuantizerTests.cs | 6 +++--- .../Processors/Quantization/WuQuantizerTests.cs | 6 +++--- .../Quantization/QuantizedImageTests.cs | 12 ++++++------ .../Quantization/WuQuantizerTests.cs | 10 +++++----- 22 files changed, 84 insertions(+), 77 deletions(-) rename src/ImageSharp/Processing/Processors/Quantization/{OctreeFrameQuantizer{TPixel}.cs => OctreeQuantizer{TPixel}.cs} (97%) rename src/ImageSharp/Processing/Processors/Quantization/{PaletteFrameQuantizer{TPixel}.cs => PaletteQuantizer{TPixel}.cs} (91%) rename src/ImageSharp/Processing/Processors/Quantization/{WuFrameQuantizer{TPixel}.cs => WuQuantizer{TPixel}.cs} (98%) diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 23ae62c7a1..d692292b09 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Advanced private static void AotCompileOctreeQuantizer() where TPixel : unmanaged, IPixel { - using (var test = new OctreeFrameQuantizer(Configuration.Default, new OctreeQuantizer().Options)) + using (var test = new OctreeQuantizer(Configuration.Default, new OctreeQuantizer().Options)) { var frame = new ImageFrame(Configuration.Default, 1, 1); test.QuantizeFrame(frame, frame.Bounds()); @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.Advanced private static void AotCompileWuQuantizer() where TPixel : unmanaged, IPixel { - using (var test = new WuFrameQuantizer(Configuration.Default, new WuQuantizer().Options)) + using (var test = new WuQuantizer(Configuration.Default, new WuQuantizer().Options)) { var frame = new ImageFrame(Configuration.Default, 1, 1); test.QuantizeFrame(frame, frame.Bounds()); @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.Advanced private static void AotCompilePaletteQuantizer() where TPixel : unmanaged, IPixel { - using (var test = (PaletteFrameQuantizer)new PaletteQuantizer(Array.Empty()).CreateFrameQuantizer(Configuration.Default)) + using (var test = (PaletteQuantizer)new PaletteQuantizer(Array.Empty()).CreatePixelSpecificQuantizer(Configuration.Default)) { var frame = new ImageFrame(Configuration.Default, 1, 1); test.QuantizeFrame(frame, frame.Bounds()); diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 7d27995038..c7c53037fd 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -336,7 +336,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp private void Write8BitColor(Stream stream, ImageFrame image, Span colorPalette) where TPixel : unmanaged, IPixel { - using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration); + using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration); using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(image, image.Bounds()); ReadOnlySpan quantizedColors = quantized.Palette.Span; diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 62410025c6..ae5f62443e 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Gif // Quantize the image returning a palette. IndexedImageFrame quantized; - using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration)) + using (IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration)) { quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); } @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Formats.Gif pixelMap = new EuclideanPixelMap(this.configuration, quantized.Palette); } - using var paletteFrameQuantizer = new PaletteFrameQuantizer(this.configuration, this.quantizer.Options, pixelMap); + using var paletteFrameQuantizer = new PaletteQuantizer(this.configuration, this.quantizer.Options, pixelMap); using IndexedImageFrame paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds()); this.WriteImageData(paletteQuantized, stream); } @@ -184,12 +184,12 @@ namespace SixLabors.ImageSharp.Formats.Gif MaxColors = frameMetadata.ColorTableLength }; - using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration, options); + using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, options); quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); } else { - using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(this.configuration); + using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration); quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs index 3f490ca6f8..8cfd2af350 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Formats.Png } // Create quantized frame returning the palette and set the bit depth. - using (IFrameQuantizer frameQuantizer = options.Quantizer.CreateFrameQuantizer(image.GetConfiguration())) + using (IQuantizer frameQuantizer = options.Quantizer.CreatePixelSpecificQuantizer(image.GetConfiguration())) { ImageFrame frame = image.Frames.RootFrame; return frameQuantizer.QuantizeFrame(frame, frame.Bounds()); diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 7d30bada6e..e322afb8d2 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : struct, IFrameQuantizer + where TFrameQuantizer : struct, IQuantizer where TPixel : unmanaged, IPixel { int offsetY = bounds.Top; diff --git a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs index 8f9d82537b..8b0e1b8a89 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : struct, IFrameQuantizer + where TFrameQuantizer : struct, IQuantizer where TPixel : unmanaged, IPixel; /// diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 6862cff000..0f5a7fb55c 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : struct, IFrameQuantizer + where TFrameQuantizer : struct, IQuantizer where TPixel : unmanaged, IPixel { var ditherOperation = new QuantizeDitherRowOperation( @@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering => HashCode.Combine(this.thresholdMatrix, this.modulusX, this.modulusY); private readonly struct QuantizeDitherRowOperation : IRowOperation - where TFrameQuantizer : struct, IFrameQuantizer + where TFrameQuantizer : struct, IQuantizer where TPixel : unmanaged, IPixel { private readonly TFrameQuantizer quantizer; diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs index 4d75042ea3..c74ea4959c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs @@ -11,7 +11,7 @@ using SixLabors.ImageSharp.Processing.Processors.Dithering; namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// - /// Contains utility methods for instances. + /// Contains utility methods for instances. /// public static class FrameQuantizerUtilities { @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The pixel format. /// The frame quantizer palette. /// - /// The palette has not been built via + /// The palette has not been built via /// public static void CheckPaletteState(in ReadOnlyMemory palette) where TPixel : unmanaged, IPixel @@ -48,14 +48,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ref TFrameQuantizer quantizer, ImageFrame source, Rectangle bounds) - where TFrameQuantizer : struct, IFrameQuantizer + where TFrameQuantizer : struct, IQuantizer where TPixel : unmanaged, IPixel { Guard.NotNull(source, nameof(source)); var interest = Rectangle.Intersect(source.Bounds(), bounds); + BufferRegion region = source.PixelBuffer.GetRegion(interest); // Collect the palette. Required before the second pass runs. - quantizer.BuildPalette(source, interest); + quantizer.CollectPaletteColors(region); var destination = new IndexedImageFrame( quantizer.Configuration, @@ -83,7 +84,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ImageFrame source, IndexedImageFrame destination, Rectangle bounds) - where TFrameQuantizer : struct, IFrameQuantizer + where TFrameQuantizer : struct, IQuantizer where TPixel : unmanaged, IPixel { IDither dither = quantizer.Options.Dither; @@ -108,7 +109,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } private readonly struct RowIntervalOperation : IRowIntervalOperation - where TFrameQuantizer : struct, IFrameQuantizer + where TFrameQuantizer : struct, IQuantizer where TPixel : unmanaged, IPixel { private readonly TFrameQuantizer quantizer; diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index cc87715ebd..33ba61747c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Quantization @@ -10,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Provides methods to allow the execution of the quantization process on an image frame. /// /// The pixel format. - public interface IFrameQuantizer : IDisposable + public interface IQuantizer : IDisposable where TPixel : unmanaged, IPixel { /// @@ -27,16 +28,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Gets the quantized color palette. /// /// - /// The palette has not been built via . + /// The palette has not been built via . /// ReadOnlyMemory Palette { get; } /// - /// Builds the quantized palette from the given image frame and bounds. + /// Adds colors to the quantized palette from the given pixel source. /// - /// The source image frame. - /// The region of interest bounds. - void BuildPalette(ImageFrame source, Rectangle bounds); + /// The of source pixels to register. + void CollectPaletteColors(BufferRegion pixelRegion); /// /// Quantizes an image frame and return the resulting output pixels. diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs index 01e4b5e8a2..e59b9a6a7d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs @@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The to configure internal operations. /// The pixel format. - /// The . - IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + /// The . + IQuantizer CreatePixelSpecificQuantizer(Configuration configuration) where TPixel : unmanaged, IPixel; /// @@ -30,8 +30,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The pixel format. /// The to configure internal operations. /// The options to create the quantizer with. - /// The . - IFrameQuantizer CreateFrameQuantizer(Configuration configuration, QuantizerOptions options) + /// The . + IQuantizer CreatePixelSpecificQuantizer(Configuration configuration, QuantizerOptions options) where TPixel : unmanaged, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 9e04edef0b..02e85167d8 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -36,13 +36,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public QuantizerOptions Options { get; } /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration) where TPixel : unmanaged, IPixel - => this.CreateFrameQuantizer(configuration, this.Options); + => this.CreatePixelSpecificQuantizer(configuration, this.Options); /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, QuantizerOptions options) + public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration, QuantizerOptions options) where TPixel : unmanaged, IPixel - => new OctreeFrameQuantizer(configuration, options); + => new OctreeQuantizer(configuration, options); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs similarity index 97% rename from src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index ce2e406d4c..2a9b8d79be 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - public struct OctreeFrameQuantizer : IFrameQuantizer + public struct OctreeQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private readonly int maxColors; @@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private bool isDisposed; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The configuration which allows altering default behaviour or extending the library. /// The quantizer options defining quantization rules. [MethodImpl(InliningOptions.ShortMethod)] - public OctreeFrameQuantizer(Configuration configuration, QuantizerOptions options) + public OctreeQuantizer(Configuration configuration, QuantizerOptions options) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(options, nameof(options)); @@ -69,15 +69,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public void BuildPalette(ImageFrame source, Rectangle bounds) + public void CollectPaletteColors(BufferRegion pixelRegion) { + Rectangle bounds = pixelRegion.Rectangle; + Buffer2D source = pixelRegion.Buffer; using IMemoryOwner buffer = this.Configuration.MemoryAllocator.Allocate(bounds.Width); Span bufferSpan = buffer.GetSpan(); // Loop through each row for (int y = bounds.Top; y < bounds.Bottom; y++) { - Span row = source.GetPixelRowSpan(y).Slice(bounds.Left, bounds.Width); + Span row = source.GetRowSpan(y).Slice(bounds.Left, bounds.Width); PixelOperations.Instance.ToRgba32(this.Configuration, row, bufferSpan); for (int x = 0; x < bufferSpan.Length; x++) diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index c14ea6153f..38816a168d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -41,12 +41,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public QuantizerOptions Options { get; } /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration) where TPixel : unmanaged, IPixel - => this.CreateFrameQuantizer(configuration, this.Options); + => this.CreatePixelSpecificQuantizer(configuration, this.Options); /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, QuantizerOptions options) + public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration, QuantizerOptions options) where TPixel : unmanaged, IPixel { Guard.NotNull(options, nameof(options)); @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Color.ToPixel(configuration, this.colorPalette.Span, palette.AsSpan()); var pixelMap = new EuclideanPixelMap(configuration, palette); - return new PaletteFrameQuantizer(configuration, options, pixelMap); + return new PaletteQuantizer(configuration, options, pixelMap); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs similarity index 91% rename from src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index ade73e2d02..e40cf0c8cd 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Quantization @@ -12,19 +13,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - internal struct PaletteFrameQuantizer : IFrameQuantizer + internal struct PaletteQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private readonly EuclideanPixelMap pixelMap; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The configuration which allows altering default behaviour or extending the library. /// The quantizer options defining quantization rules. /// The pixel map for looking up color matches from a predefined palette. [MethodImpl(InliningOptions.ShortMethod)] - public PaletteFrameQuantizer( + public PaletteQuantizer( Configuration configuration, QuantizerOptions options, EuclideanPixelMap pixelMap) @@ -53,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public void BuildPalette(ImageFrame source, Rectangle bounds) + public void CollectPaletteColors(BufferRegion pixelRegion) { } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index 386caf1be3..dce7696927 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization var interest = Rectangle.Intersect(source.Bounds(), this.SourceRectangle); Configuration configuration = this.Configuration; - using IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(configuration); + using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(configuration); using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(source, interest); var operation = new RowIntervalOperation(this.SourceRectangle, source, quantized); diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index d2e33aa1f1..0f1dff1811 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -35,13 +35,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public QuantizerOptions Options { get; } /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration) where TPixel : unmanaged, IPixel - => this.CreateFrameQuantizer(configuration, this.Options); + => this.CreatePixelSpecificQuantizer(configuration, this.Options); /// - public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, QuantizerOptions options) + public IQuantizer CreatePixelSpecificQuantizer(Configuration configuration, QuantizerOptions options) where TPixel : unmanaged, IPixel - => new WuFrameQuantizer(configuration, options); + => new WuQuantizer(configuration, options); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs similarity index 98% rename from src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index d15db74e62..a83bf3b6d1 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// /// The pixel format. - internal struct WuFrameQuantizer : IFrameQuantizer + internal struct WuQuantizer : IQuantizer where TPixel : unmanaged, IPixel { private readonly MemoryAllocator memoryAllocator; @@ -77,12 +77,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private bool isDisposed; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The configuration which allows altering default behaviour or extending the library. /// The quantizer options defining quantization rules. [MethodImpl(InliningOptions.ShortMethod)] - public WuFrameQuantizer(Configuration configuration, QuantizerOptions options) + public WuQuantizer(Configuration configuration, QuantizerOptions options) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(options, nameof(options)); @@ -118,8 +118,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } /// - public void BuildPalette(ImageFrame source, Rectangle bounds) + public void CollectPaletteColors(BufferRegion pixelRegion) { + Rectangle bounds = pixelRegion.Rectangle; + Buffer2D source = pixelRegion.Buffer; + this.Build3DHistogram(source, bounds); this.Get3DMoments(this.memoryAllocator); this.BuildCube(); @@ -360,7 +363,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The source data. /// The bounds within the source image to quantize. - private void Build3DHistogram(ImageFrame source, Rectangle bounds) + private void Build3DHistogram(Buffer2D source, Rectangle bounds) { Span momentSpan = this.momentsOwner.GetSpan(); @@ -370,7 +373,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization for (int y = bounds.Top; y < bounds.Bottom; y++) { - Span row = source.GetPixelRowSpan(y).Slice(bounds.Left, bounds.Width); + Span row = source.GetRowSpan(y).Slice(bounds.Left, bounds.Width); PixelOperations.Instance.ToRgba32(this.Configuration, row, bufferSpan); for (int x = 0; x < bufferSpan.Length; x++) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs index bb7921d686..dd27164f31 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization public void OctreeQuantizerCanCreateFrameQuantizer() { var quantizer = new OctreeQuantizer(); - IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.NotNull(frameQuantizer.Options); @@ -47,14 +47,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization frameQuantizer.Dispose(); quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = null }); - frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.Null(frameQuantizer.Options.Dither); frameQuantizer.Dispose(); quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = KnownDitherings.Atkinson }); - frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.Equal(KnownDitherings.Atkinson, frameQuantizer.Options.Dither); frameQuantizer.Dispose(); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs index 3c1fa11ab0..acc9a0e012 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization public void PaletteQuantizerCanCreateFrameQuantizer() { var quantizer = new PaletteQuantizer(Palette); - IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.NotNull(frameQuantizer.Options); @@ -49,14 +49,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization frameQuantizer.Dispose(); quantizer = new PaletteQuantizer(Palette, new QuantizerOptions { Dither = null }); - frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.Null(frameQuantizer.Options.Dither); frameQuantizer.Dispose(); quantizer = new PaletteQuantizer(Palette, new QuantizerOptions { Dither = KnownDitherings.Atkinson }); - frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.Equal(KnownDitherings.Atkinson, frameQuantizer.Options.Dither); frameQuantizer.Dispose(); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs index eb9d738e9a..d78e9254ca 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization public void WuQuantizerCanCreateFrameQuantizer() { var quantizer = new WuQuantizer(); - IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.NotNull(frameQuantizer.Options); @@ -47,14 +47,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization frameQuantizer.Dispose(); quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }); - frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.Null(frameQuantizer.Options.Dither); frameQuantizer.Dispose(); quantizer = new WuQuantizer(new QuantizerOptions { Dither = KnownDitherings.Atkinson }); - frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + frameQuantizer = quantizer.CreatePixelSpecificQuantizer(Configuration.Default); Assert.NotNull(frameQuantizer); Assert.Equal(KnownDitherings.Atkinson, frameQuantizer.Options.Dither); frameQuantizer.Dispose(); diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 7945741b01..86229a7b61 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -27,22 +27,22 @@ namespace SixLabors.ImageSharp.Tests Assert.NotNull(octree.Options.Dither); Assert.NotNull(wu.Options.Dither); - using (IFrameQuantizer quantizer = werner.CreateFrameQuantizer(this.Configuration)) + using (IQuantizer quantizer = werner.CreatePixelSpecificQuantizer(this.Configuration)) { Assert.NotNull(quantizer.Options.Dither); } - using (IFrameQuantizer quantizer = webSafe.CreateFrameQuantizer(this.Configuration)) + using (IQuantizer quantizer = webSafe.CreatePixelSpecificQuantizer(this.Configuration)) { Assert.NotNull(quantizer.Options.Dither); } - using (IFrameQuantizer quantizer = octree.CreateFrameQuantizer(this.Configuration)) + using (IQuantizer quantizer = octree.CreatePixelSpecificQuantizer(this.Configuration)) { Assert.NotNull(quantizer.Options.Dither); } - using (IFrameQuantizer quantizer = wu.CreateFrameQuantizer(this.Configuration)) + using (IQuantizer quantizer = wu.CreatePixelSpecificQuantizer(this.Configuration)) { Assert.NotNull(quantizer.Options.Dither); } @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(this.Configuration)) + using (IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.Configuration)) using (IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { int index = this.GetTransparentIndex(quantized); @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(this.Configuration)) + using (IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.Configuration)) using (IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { int index = this.GetTransparentIndex(quantized); diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index 37b8cab60f..75e88ba793 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization using var image = new Image(config, 1, 1, Color.Black); ImageFrame frame = image.Frames.RootFrame; - using IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization using var image = new Image(config, 1, 1, default(Rgba32)); ImageFrame frame = image.Frames.RootFrame; - using IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; - using IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(256, result.Palette.Length); @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization var quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }); ImageFrame frame = image.Frames.RootFrame; - using IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); Assert.Equal(48, result.Palette.Length); @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization var quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }); ImageFrame frame = image.Frames.RootFrame; - using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) + using (IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config)) using (IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) { Assert.Equal(4 * 8, result.Palette.Length); From 8551b8bc12ec4dc5b445ad3d1a803d0a3d2ae85c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 30 Apr 2020 03:13:15 +0200 Subject: [PATCH 192/213] fix style issue --- .../Quantization/PixelSamplingStrategyTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs index 0787b56a9c..3ee7fdb31a 100644 --- a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs +++ b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.True(visitRatio <= 1.1, $"{visitedPixels}>{maximumPixels}"); } - static void PaintWhite(BufferRegion region) + private static void PaintWhite(BufferRegion region) { var white = new L8(255); for (int y = 0; y < region.Height; y++) @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization } } - private Image CreateTestImage(int width, int height, int noOfFrames, bool paintWhite = false) + private static Image CreateTestImage(int width, int height, int noOfFrames, bool paintWhite = false) { L8 bg = paintWhite ? new L8(255) : default; var image = new Image(width, height, bg); From 097b9dd4fdcde29ca51332a913584db861bad3da Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 30 Apr 2020 04:17:54 +0200 Subject: [PATCH 193/213] BuildPaletteAndQuantizeFrame, use IPixelSamplingStrategy in GifEncoder --- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoder.cs | 6 ++- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 21 ++++++-- .../Formats/Gif/IGifEncoderOptions.cs | 5 ++ .../Formats/Png/PngEncoderOptionsHelpers.cs | 2 +- .../DefaultPixelSamplingStrategy.cs | 31 +++++++++--- ...tizer{TPixel}.cs => IQuantizer{TPixel}.cs} | 8 ++- .../Quantization/OctreeQuantizer{TPixel}.cs | 6 +-- .../Quantization/PaletteQuantizer{TPixel}.cs | 4 +- .../Quantization/QuantizeProcessor{TPixel}.cs | 2 +- ...izerUtilities.cs => QuantizerUtilities.cs} | 49 ++++++++++++++++--- .../Quantization/WuQuantizer{TPixel}.cs | 6 +-- .../Formats/Gif/GifEncoderTests.cs | 26 ++++++---- .../PixelSamplingStrategyTests.cs | 2 +- .../Quantization/QuantizedImageTests.cs | 4 +- .../Quantization/WuQuantizerTests.cs | 10 ++-- 16 files changed, 136 insertions(+), 48 deletions(-) rename src/ImageSharp/Processing/Processors/Quantization/{IFrameQuantizer{TPixel}.cs => IQuantizer{TPixel}.cs} (85%) rename src/ImageSharp/Processing/Processors/Quantization/{FrameQuantizerUtilities.cs => QuantizerUtilities.cs} (77%) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index c7c53037fd..2d6b623a18 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -337,7 +337,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp where TPixel : unmanaged, IPixel { using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration); - using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(image, image.Bounds()); + using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds()); ReadOnlySpan quantizedColors = quantized.Palette.Span; var color = default(Rgba32); diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index aa276cd986..e95a1ae32d 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -25,7 +25,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public GifColorTableMode? ColorTableMode { get; set; } - internal IPixelSamplingStrategy GlobalPixelSamplingStrategy { get; set; } + /// + /// Gets or sets the used for quantization + /// when building a global color table in case of . + /// + public IPixelSamplingStrategy GlobalPixelSamplingStrategy { get; set; } = new DefaultPixelSamplingStrategy(); /// public void Encode(Image image, Stream stream) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ae5f62443e..0f20630601 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -49,6 +49,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private int bitDepth; + /// + /// The pixel sampling strategy for global quantization. + /// + private IPixelSamplingStrategy pixelSamplingStrategy; + /// /// Initializes a new instance of the class. /// @@ -60,6 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.memoryAllocator = configuration.MemoryAllocator; this.quantizer = options.Quantizer; this.colorTableMode = options.ColorTableMode; + this.pixelSamplingStrategy = options.GlobalPixelSamplingStrategy; } /// @@ -81,9 +87,18 @@ namespace SixLabors.ImageSharp.Formats.Gif // Quantize the image returning a palette. IndexedImageFrame quantized; + using (IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration)) { - quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); + if (useGlobalTable) + { + frameQuantizer.BuildPalette(this.pixelSamplingStrategy, image); + quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); + } + else + { + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image.Frames.RootFrame, image.Bounds()); + } } // Get the number of bits. @@ -185,12 +200,12 @@ namespace SixLabors.ImageSharp.Formats.Gif }; using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, options); - quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); } else { using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration); - quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); } } diff --git a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs index 752e6866fe..151e1a23d6 100644 --- a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs @@ -22,5 +22,10 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Gets the color table mode: Global or local. /// GifColorTableMode? ColorTableMode { get; } + + /// + /// Gets the used for quantization when building a global color table. + /// + IPixelSamplingStrategy GlobalPixelSamplingStrategy { get; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs index 8cfd2af350..99e64c2fb4 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Png using (IQuantizer frameQuantizer = options.Quantizer.CreatePixelSpecificQuantizer(image.GetConfiguration())) { ImageFrame frame = image.Frames.RootFrame; - return frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + return frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs index 6653259c57..660d41bd51 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs @@ -15,14 +15,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public class DefaultPixelSamplingStrategy : IPixelSamplingStrategy { // TODO: This value shall be determined by benchmarking. - // (Maximum quality while decoding time is still tolerable.) - private const int DefaultMaximumPixels = 8192 * 8192; + // A smaller value should likely work well, providing better perf. + private const int DefaultMaximumPixels = 4096 * 4096; /// /// Initializes a new instance of the class. /// public DefaultPixelSamplingStrategy() - : this(DefaultMaximumPixels) + : this(DefaultMaximumPixels, 0.1) { } @@ -30,10 +30,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Initializes a new instance of the class. /// /// The maximum number of pixels to process. - public DefaultPixelSamplingStrategy(int maximumPixels) + /// always scan at least this portion of total pixels within the image. + public DefaultPixelSamplingStrategy(int maximumPixels, double minimumScanRatio) { Guard.MustBeGreaterThan(maximumPixels, 0, nameof(maximumPixels)); this.MaximumPixels = maximumPixels; + this.MinimumScanRatio = minimumScanRatio; } /// @@ -41,11 +43,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public long MaximumPixels { get; } + /// + /// Gets a value indicating: always scan at least this portion of total pixels within the image. + /// The default is 0.1 (10%). + /// + public double MinimumScanRatio { get; } + /// public IEnumerable> EnumeratePixelRegions(Image image) where TPixel : unmanaged, IPixel { - long maximumPixels = Math.Min(MaximumPixels, (long)image.Width * image.Height * image.Frames.Count); + long maximumPixels = Math.Min(this.MaximumPixels, (long)image.Width * image.Height * image.Frames.Count); long maxNumberOfRows = maximumPixels / image.Width; long totalNumberOfRows = (long)image.Height * image.Frames.Count; @@ -61,8 +69,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { double r = maxNumberOfRows / (double)totalNumberOfRows; - r = Math.Round(r, 1); // Use a rough approximation to make sure we don't leave out large contiguous regions: - r = Math.Max(0.1, r); // always visit at least 10% of the image + // Use a rough approximation to make sure we don't leave out large contiguous regions: + if (maxNumberOfRows > 200) + { + r = Math.Round(r, 2); + } + else + { + r = Math.Round(r, 1); + } + + r = Math.Max(this.MinimumScanRatio, r); // always visit the minimum defined portion of the image. var ratio = new Rational(r); diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs similarity index 85% rename from src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs rename to src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs index 33ba61747c..0c3c6a83a4 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Gets the quantized color palette. ///
/// - /// The palette has not been built via . + /// The palette has not been built via . /// ReadOnlyMemory Palette { get; } @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Adds colors to the quantized palette from the given pixel source. ///
/// The of source pixels to register. - void CollectPaletteColors(BufferRegion pixelRegion); + void AddPaletteColors(BufferRegion pixelRegion); /// /// Quantizes an image frame and return the resulting output pixels. @@ -46,6 +46,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// A representing a quantized version of the source frame pixels. /// + /// + /// Only executes the second (quantization) step. The palette has to be built by calling . + /// To run both steps, use . + /// IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds); /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index 2a9b8d79be..c74e8ef864 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -62,14 +62,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { get { - FrameQuantizerUtilities.CheckPaletteState(in this.palette); + QuantizerUtilities.CheckPaletteState(in this.palette); return this.palette; } } /// [MethodImpl(InliningOptions.ShortMethod)] - public void CollectPaletteColors(BufferRegion pixelRegion) + public void AddPaletteColors(BufferRegion pixelRegion) { Rectangle bounds = pixelRegion.Rectangle; Buffer2D source = pixelRegion.Buffer; @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index e40cf0c8cd..44daef84d6 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -50,11 +50,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] - public void CollectPaletteColors(BufferRegion pixelRegion) + public void AddPaletteColors(BufferRegion pixelRegion) { } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index dce7696927..9bc94831aa 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Configuration configuration = this.Configuration; using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(configuration); - using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(source, interest); + using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(source, interest); var operation = new RowIntervalOperation(this.SourceRectangle, source, quantized); ParallelRowIterator.IterateRowIntervals( diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs similarity index 77% rename from src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs rename to src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs index c74ea4959c..a3f13e00da 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Contains utility methods for instances. /// - public static class FrameQuantizerUtilities + public static class QuantizerUtilities { /// /// Helper method for throwing an exception when a frame quantizer palette has @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The pixel format. /// The frame quantizer palette. /// - /// The palette has not been built via + /// The palette has not been built via /// public static void CheckPaletteState(in ReadOnlyMemory palette) where TPixel : unmanaged, IPixel @@ -33,12 +33,39 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + /// + /// Execute both steps of the quantization. + /// + /// The pixel specific quantizer. + /// The source image frame to quantize. + /// The bounds within the frame to quantize. + /// The pixel type. + /// + /// A representing a quantized version of the source frame pixels. + /// + public static IndexedImageFrame BuildPaletteAndQuantizeFrame( + this IQuantizer quantizer, + ImageFrame source, + Rectangle bounds) + where TPixel : unmanaged, IPixel + { + Guard.NotNull(quantizer, nameof(quantizer)); + Guard.NotNull(source, nameof(source)); + + var interest = Rectangle.Intersect(source.Bounds(), bounds); + BufferRegion region = source.PixelBuffer.GetRegion(interest); + + // Collect the palette. Required before the second pass runs. + quantizer.AddPaletteColors(region); + return quantizer.QuantizeFrame(source, bounds); + } + /// /// Quantizes an image frame and return the resulting output pixels. /// /// The type of frame quantizer. /// The pixel format. - /// The frame quantizer. + /// The pixel specific quantizer. /// The source image frame to quantize. /// The bounds within the frame to quantize. /// @@ -53,10 +80,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { Guard.NotNull(source, nameof(source)); var interest = Rectangle.Intersect(source.Bounds(), bounds); - BufferRegion region = source.PixelBuffer.GetRegion(interest); - - // Collect the palette. Required before the second pass runs. - quantizer.CollectPaletteColors(region); var destination = new IndexedImageFrame( quantizer.Configuration, @@ -78,6 +101,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return destination; } + internal static void BuildPalette( + this IQuantizer quantizer, + IPixelSamplingStrategy pixelSamplingStrategy, + Image image) + where TPixel : unmanaged, IPixel + { + foreach (BufferRegion region in pixelSamplingStrategy.EnumeratePixelRegions(image)) + { + quantizer.AddPaletteColors(region); + } + } + [MethodImpl(InliningOptions.ShortMethod)] private static void SecondPass( ref TFrameQuantizer quantizer, diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index a83bf3b6d1..3f0822bed0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -112,13 +112,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { get { - FrameQuantizerUtilities.CheckPaletteState(in this.palette); + QuantizerUtilities.CheckPaletteState(in this.palette); return this.palette; } } /// - public void CollectPaletteColors(BufferRegion pixelRegion) + public void AddPaletteColors(BufferRegion pixelRegion) { Rectangle bounds = pixelRegion.Rectangle; Buffer2D source = pixelRegion.Buffer; @@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => FrameQuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); /// public readonly byte GetQuantizedColor(TPixel color, out TPixel match) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index cbaed758dc..bfe950d4fb 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -134,27 +134,35 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } [Theory] - [WithFile(TestImages.Gif.GlobalQuantizationTest, PixelTypes.Rgba32)] - public void Encode_GlobalPalette_QuantizeMultipleFrames(TestImageProvider provider) + [WithFile(TestImages.Gif.GlobalQuantizationTest, PixelTypes.Rgba32, 427500, 0.1)] + [WithFile(TestImages.Gif.GlobalQuantizationTest, PixelTypes.Rgba32, 200000, 0.1)] + [WithFile(TestImages.Gif.GlobalQuantizationTest, PixelTypes.Rgba32, 100000, 0.1)] + [WithFile(TestImages.Gif.GlobalQuantizationTest, PixelTypes.Rgba32, 50000, 0.1)] + [WithFile(TestImages.Gif.Cheers, PixelTypes.Rgba32, 4000000, 0.01)] + [WithFile(TestImages.Gif.Cheers, PixelTypes.Rgba32, 1000000, 0.01)] + public void Encode_GlobalPalette_DefaultPixelSamplingStrategy(TestImageProvider provider, int maxPixels, double scanRatio) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); var encoder = new GifEncoder() { - ColorTableMode = GifColorTableMode.Global + ColorTableMode = GifColorTableMode.Global, + GlobalPixelSamplingStrategy = new DefaultPixelSamplingStrategy(maxPixels, scanRatio) }; string testOutputFile = provider.Utility.SaveTestOutputFile( image, "gif", encoder, - appendPixelTypeToFileName: false, - appendSourceFileOrDescription: false); - - IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(testOutputFile); - using var encoded = Image.Load(testOutputFile, referenceDecoder); - ValidatorComparer.VerifySimilarity(image, encoded); + testOutputDetails: $"{maxPixels}_{scanRatio}", + appendPixelTypeToFileName: false); + + // TODO: For proper regression testing of gifs, use a multi-frame reference output, or find a working reference decoder. + // IImageDecoder referenceDecoder = TestEnvironment.Ge + // ReferenceDecoder(testOutputFile); + // using var encoded = Image.Load(testOutputFile, referenceDecoder); + // ValidatorComparer.VerifySimilarity(image, encoded); } [Fact] diff --git a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs index 3ee7fdb31a..40eafc787a 100644 --- a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs +++ b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization { using Image image = CreateTestImage(width, height, noOfFrames); - var strategy = new DefaultPixelSamplingStrategy(maximumNumberOfPixels); + var strategy = new DefaultPixelSamplingStrategy(maximumNumberOfPixels, 0.1); long visitedPixels = 0; foreach (BufferRegion region in strategy.EnumeratePixelRegions(image)) diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 86229a7b61..067604f82a 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { using (IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.Configuration)) - using (IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) + using (IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds())) { int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelRowSpan(0)[0]); @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { using (IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.Configuration)) - using (IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) + using (IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds())) { int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelRowSpan(0)[0]); diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index 75e88ba793..2a9280d6d6 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); - using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame result = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.Width); @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); - using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame result = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.Width); @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); - using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame result = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); Assert.Equal(256, result.Palette.Length); Assert.Equal(1, result.Width); @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); - using IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + using IndexedImageFrame result = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds()); Assert.Equal(48, result.Palette.Length); } @@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization ImageFrame frame = image.Frames.RootFrame; using (IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config)) - using (IndexedImageFrame result = frameQuantizer.QuantizeFrame(frame, frame.Bounds())) + using (IndexedImageFrame result = frameQuantizer.BuildPaletteAndQuantizeFrame(frame, frame.Bounds())) { Assert.Equal(4 * 8, result.Palette.Length); Assert.Equal(1, result.Width); From 5db749e5c70ba1194e96ff45d4b6853e89453846 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 30 Apr 2020 04:18:38 +0200 Subject: [PATCH 194/213] Revert "use only netcoreapp3.1" This reverts commit 173659669e428f7c18c704c7ea50aeca5e2c93b5. --- src/ImageSharp/ImageSharp.csproj | 3 +-- tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 3 +-- .../ImageSharp.Tests.ProfilingSandbox.csproj | 3 +-- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 185638d19a..baf4a2ce19 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -10,8 +10,7 @@ $(packageversion) 0.0.1 - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472 true true diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 101d279569..f380d0a6a9 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -5,8 +5,7 @@ ImageSharp.Benchmarks Exe SixLabors.ImageSharp.Benchmarks - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 false false diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index f9e6c9da59..7c80316930 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -8,8 +8,7 @@ false SixLabors.ImageSharp.Tests.ProfilingSandbox win7-x64 - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 SixLabors.ImageSharp.Tests.ProfilingSandbox.Program false diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index d5c8ef16ee..fdb280ca99 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -2,8 +2,7 @@ - - netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 True True SixLabors.ImageSharp.Tests From 200ef9ffbeb44d7ad088834a62c6c092fc6e71a8 Mon Sep 17 00:00:00 2001 From: Brian Popow <38701097+brianpopow@users.noreply.github.com> Date: Thu, 30 Apr 2020 11:22:47 +0200 Subject: [PATCH 195/213] ExcludeAll = ~None Co-Authored-By: James Jackson-South --- src/ImageSharp/Formats/Png/PngChunkFilter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngChunkFilter.cs b/src/ImageSharp/Formats/Png/PngChunkFilter.cs index f859d44dac..04f27fb73b 100644 --- a/src/ImageSharp/Formats/Png/PngChunkFilter.cs +++ b/src/ImageSharp/Formats/Png/PngChunkFilter.cs @@ -39,6 +39,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// All possible optimizations. /// - ExcludeAll = ExcludePhysicalChunk | ExcludeGammaChunk | ExcludeExifChunk | ExcludeTextChunks + ExcludeAll = ~None } } From f9c2f6ade67a4f6f2a9e9eeb92d3205ec832730e Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 30 Apr 2020 11:20:29 +0200 Subject: [PATCH 196/213] Improve exclude filter test to also check presence of expected chunks --- .../Formats/Png/IPngEncoderOptions.cs | 2 +- .../Formats/Png/PngEncoderTests.Chunks.cs | 36 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 48fd7447dd..e5d0b09cf7 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Png PngInterlaceMode? InterlaceMethod { get; } /// - /// Gets the optimize method. + /// Gets chunk filter method. /// PngChunkFilter? ChunkFilter { get; } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs index 9d28fd89b0..fa15448164 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs @@ -158,22 +158,41 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png using Image input = testFile.CreateRgba32Image(); using var memStream = new MemoryStream(); var encoder = new PngEncoder() { ChunkFilter = chunkFilter, TextCompressionThreshold = 8 }; + var expectedChunkTypes = new Dictionary() + { + { PngChunkType.Header, false }, + { PngChunkType.Gamma, false }, + { PngChunkType.Palette, false }, + { PngChunkType.InternationalText, false }, + { PngChunkType.Text, false }, + { PngChunkType.CompressedText, false }, + { PngChunkType.Exif, false }, + { PngChunkType.Physical, false }, + { PngChunkType.Data, false }, + { PngChunkType.End, false } + }; var excludedChunkTypes = new List(); switch (chunkFilter) { case PngChunkFilter.ExcludeGammaChunk: excludedChunkTypes.Add(PngChunkType.Gamma); + expectedChunkTypes.Remove(PngChunkType.Gamma); break; case PngChunkFilter.ExcludeExifChunk: excludedChunkTypes.Add(PngChunkType.Exif); + expectedChunkTypes.Remove(PngChunkType.Exif); break; case PngChunkFilter.ExcludePhysicalChunk: excludedChunkTypes.Add(PngChunkType.Physical); + expectedChunkTypes.Remove(PngChunkType.Physical); break; case PngChunkFilter.ExcludeTextChunks: excludedChunkTypes.Add(PngChunkType.Text); excludedChunkTypes.Add(PngChunkType.InternationalText); excludedChunkTypes.Add(PngChunkType.CompressedText); + expectedChunkTypes.Remove(PngChunkType.Text); + expectedChunkTypes.Remove(PngChunkType.InternationalText); + expectedChunkTypes.Remove(PngChunkType.CompressedText); break; case PngChunkFilter.ExcludeAll: excludedChunkTypes.Add(PngChunkType.Gamma); @@ -182,6 +201,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png excludedChunkTypes.Add(PngChunkType.Text); excludedChunkTypes.Add(PngChunkType.InternationalText); excludedChunkTypes.Add(PngChunkType.CompressedText); + expectedChunkTypes.Remove(PngChunkType.Gamma); + expectedChunkTypes.Remove(PngChunkType.Exif); + expectedChunkTypes.Remove(PngChunkType.Physical); + expectedChunkTypes.Remove(PngChunkType.Text); + expectedChunkTypes.Remove(PngChunkType.InternationalText); + expectedChunkTypes.Remove(PngChunkType.CompressedText); break; } @@ -197,9 +222,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); var chunkType = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); Assert.False(excludedChunkTypes.Contains(chunkType), $"{chunkType} chunk should have been excluded"); + if (expectedChunkTypes.ContainsKey(chunkType)) + { + expectedChunkTypes[chunkType] = true; + } bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); } + + // all expected chunk types should have been seen at least once. + foreach (PngChunkType chunkType in expectedChunkTypes.Keys) + { + Assert.True(expectedChunkTypes[chunkType], $"We expect {chunkType} chunk to be present at least once"); + } } [Fact] @@ -215,7 +250,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png PngChunkType.Header, PngChunkType.Gamma, PngChunkType.Palette, - PngChunkType.Transparency, PngChunkType.InternationalText, PngChunkType.Text, PngChunkType.CompressedText, From bedd0a91fb2a2c0c61e05ef1af4322c3a54880cd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 30 Apr 2020 19:40:06 +0100 Subject: [PATCH 197/213] BufferRegion => Buffer2DRegion --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 +- .../Jpeg/Components/Block8x8F.ScaledCopyTo.cs | 2 +- src/ImageSharp/Memory/Buffer2DExtensions.cs | 22 ++++++------ ...ufferRegion{T}.cs => Buffer2DRegion{T}.cs} | 36 +++++++++---------- .../DefaultPixelSamplingStrategy.cs | 4 +-- .../ExtensivePixelSamplingStrategy.cs | 2 +- .../Quantization/IPixelSamplingStrategy.cs | 4 +-- .../Quantization/IQuantizer{TPixel}.cs | 4 +-- .../Quantization/OctreeQuantizer{TPixel}.cs | 2 +- .../Quantization/PaletteQuantizer{TPixel}.cs | 2 +- .../Quantization/QuantizerUtilities.cs | 4 +-- .../Quantization/WuQuantizer{TPixel}.cs | 2 +- .../Resize/ResizeProcessor{TPixel}.cs | 2 +- .../Transforms/Resize/ResizeWorker.cs | 4 +-- .../BlockOperations/Block8x8F_CopyTo2x2.cs | 2 +- .../Jpg/Block8x8FTests.CopyToBufferArea.cs | 4 +-- .../Memory/BufferAreaTests.cs | 14 ++++---- .../PixelSamplingStrategyTests.cs | 6 ++-- 18 files changed, 59 insertions(+), 59 deletions(-) rename src/ImageSharp/Memory/{BufferRegion{T}.cs => Buffer2DRegion{T}.cs} (79%) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index ba94851f8e..2d8bd319d7 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -543,7 +543,7 @@ namespace SixLabors.ImageSharp.Formats.Gif return; } - BufferRegion pixelRegion = frame.PixelBuffer.GetRegion(this.restoreArea.Value); + Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(this.restoreArea.Value); pixelRegion.Clear(); this.restoreArea = null; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs index 2fbc817079..82a013f70b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical scale factors. /// [MethodImpl(InliningOptions.ShortMethod)] - public void ScaledCopyTo(in BufferRegion region, int horizontalScale, int verticalScale) + public void ScaledCopyTo(in Buffer2DRegion region, int horizontalScale, int verticalScale) { ref float areaOrigin = ref region.GetReferenceToOrigin(); this.ScaledCopyTo(ref areaOrigin, region.Stride, horizontalScale, verticalScale); diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index d61ac9087a..11c61f56cc 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -80,29 +80,29 @@ namespace SixLabors.ImageSharp.Memory } /// - /// Return a to the subarea represented by 'rectangle' + /// Return a to the subregion represented by 'rectangle' /// /// The element type /// The - /// The rectangle subarea - /// The - internal static BufferRegion GetRegion(this Buffer2D buffer, in Rectangle rectangle) + /// The rectangle subregion + /// The + internal static Buffer2DRegion GetRegion(this Buffer2D buffer, Rectangle rectangle) where T : unmanaged => - new BufferRegion(buffer, rectangle); + new Buffer2DRegion(buffer, rectangle); - internal static BufferRegion GetRegion(this Buffer2D buffer, int x, int y, int width, int height) + internal static Buffer2DRegion GetRegion(this Buffer2D buffer, int x, int y, int width, int height) where T : unmanaged => - new BufferRegion(buffer, new Rectangle(x, y, width, height)); + new Buffer2DRegion(buffer, new Rectangle(x, y, width, height)); /// - /// Return a to the whole area of 'buffer' + /// Return a to the whole area of 'buffer' /// /// The element type /// The - /// The - internal static BufferRegion GetRegion(this Buffer2D buffer) + /// The + internal static Buffer2DRegion GetRegion(this Buffer2D buffer) where T : unmanaged => - new BufferRegion(buffer); + new Buffer2DRegion(buffer); /// /// Returns the size of the buffer. diff --git a/src/ImageSharp/Memory/BufferRegion{T}.cs b/src/ImageSharp/Memory/Buffer2DRegion{T}.cs similarity index 79% rename from src/ImageSharp/Memory/BufferRegion{T}.cs rename to src/ImageSharp/Memory/Buffer2DRegion{T}.cs index 901c3217ba..b22307a1d5 100644 --- a/src/ImageSharp/Memory/BufferRegion{T}.cs +++ b/src/ImageSharp/Memory/Buffer2DRegion{T}.cs @@ -9,16 +9,16 @@ namespace SixLabors.ImageSharp.Memory /// Represents a rectangular region inside a 2D memory buffer (). /// /// The element type. - public readonly struct BufferRegion + public readonly struct Buffer2DRegion where T : unmanaged { /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The . /// The defining a rectangular area within the buffer. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BufferRegion(Buffer2D buffer, Rectangle rectangle) + public Buffer2DRegion(Buffer2D buffer, Rectangle rectangle) { DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle)); DebugGuard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle)); @@ -30,11 +30,11 @@ namespace SixLabors.ImageSharp.Memory } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BufferRegion(Buffer2D buffer) + public Buffer2DRegion(Buffer2D buffer) : this(buffer, buffer.FullRectangle()) { } @@ -98,27 +98,27 @@ namespace SixLabors.ImageSharp.Memory } /// - /// Returns a sub-area as . (Similar to .) + /// Returns a subregion as . (Similar to .) /// - /// The x index at the subarea origin. - /// The y index at the subarea origin. - /// The desired width of the subarea. - /// The desired height of the subarea. - /// The subarea + /// The x index at the subregion origin. + /// The y index at the subregion origin. + /// The desired width of the subregion. + /// The desired height of the subregion. + /// The subregion [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BufferRegion GetSubArea(int x, int y, int width, int height) + public Buffer2DRegion GetSubRegion(int x, int y, int width, int height) { var rectangle = new Rectangle(x, y, width, height); - return this.GetSubArea(rectangle); + return this.GetSubRegion(rectangle); } /// - /// Returns a sub-area as . (Similar to .) + /// Returns a subregion as . (Similar to .) /// - /// The specifying the boundaries of the subarea - /// The subarea + /// The specifying the boundaries of the subregion + /// The subregion [MethodImpl(MethodImplOptions.AggressiveInlining)] - public BufferRegion GetSubArea(Rectangle rectangle) + public Buffer2DRegion GetSubRegion(Rectangle rectangle) { DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle)); DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle)); @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.Memory int x = this.Rectangle.X + rectangle.X; int y = this.Rectangle.Y + rectangle.Y; rectangle = new Rectangle(x, y, rectangle.Width, rectangle.Height); - return new BufferRegion(this.Buffer, rectangle); + return new Buffer2DRegion(this.Buffer, rectangle); } /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs index 660d41bd51..d2bf06bcde 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public double MinimumScanRatio { get; } /// - public IEnumerable> EnumeratePixelRegions(Image image) + public IEnumerable> EnumeratePixelRegions(Image image) where TPixel : unmanaged, IPixel { long maximumPixels = Math.Min(this.MaximumPixels, (long)image.Width * image.Height * image.Frames.Count); @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - BufferRegion GetRow(int pos) + Buffer2DRegion GetRow(int pos) { int frameIdx = pos / image.Height; int y = pos % image.Height; diff --git a/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs index e2774850a0..8ef05640aa 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public class ExtensivePixelSamplingStrategy : IPixelSamplingStrategy { /// - public IEnumerable> EnumeratePixelRegions(Image image) + public IEnumerable> EnumeratePixelRegions(Image image) where TPixel : unmanaged, IPixel { foreach (ImageFrame frame in image.Frames) diff --git a/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs index 71b20174db..6c2e3bd882 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs @@ -13,12 +13,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public interface IPixelSamplingStrategy { /// - /// Enumerates pixel regions within the image as . + /// Enumerates pixel regions within the image as . /// /// The image. /// The pixel type. /// An enumeration of pixel regions. - IEnumerable> EnumeratePixelRegions(Image image) + IEnumerable> EnumeratePixelRegions(Image image) where TPixel : unmanaged, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs index 0c3c6a83a4..26c906f060 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs @@ -35,8 +35,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Adds colors to the quantized palette from the given pixel source. /// - /// The of source pixels to register. - void AddPaletteColors(BufferRegion pixelRegion); + /// The of source pixels to register. + void AddPaletteColors(Buffer2DRegion pixelRegion); /// /// Quantizes an image frame and return the resulting output pixels. diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index c74e8ef864..7fefda3f13 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public void AddPaletteColors(BufferRegion pixelRegion) + public void AddPaletteColors(Buffer2DRegion pixelRegion) { Rectangle bounds = pixelRegion.Rectangle; Buffer2D source = pixelRegion.Buffer; diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index 44daef84d6..82ff572fa5 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// [MethodImpl(InliningOptions.ShortMethod)] - public void AddPaletteColors(BufferRegion pixelRegion) + public void AddPaletteColors(Buffer2DRegion pixelRegion) { } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs index a3f13e00da..1fe69ea305 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.NotNull(source, nameof(source)); var interest = Rectangle.Intersect(source.Bounds(), bounds); - BufferRegion region = source.PixelBuffer.GetRegion(interest); + Buffer2DRegion region = source.PixelBuffer.GetRegion(interest); // Collect the palette. Required before the second pass runs. quantizer.AddPaletteColors(region); @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Image image) where TPixel : unmanaged, IPixel { - foreach (BufferRegion region in pixelSamplingStrategy.EnumeratePixelRegions(image)) + foreach (Buffer2DRegion region in pixelSamplingStrategy.EnumeratePixelRegions(image)) { quantizer.AddPaletteColors(region); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index 3f0822bed0..5e086feaa9 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } /// - public void AddPaletteColors(BufferRegion pixelRegion) + public void AddPaletteColors(Buffer2DRegion pixelRegion) { Rectangle bounds = pixelRegion.Rectangle; Buffer2D source = pixelRegion.Buffer; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 630c88bac7..09d95c8acd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms PixelConversionModifiers conversionModifiers = PixelConversionModifiers.Premultiply.ApplyCompanding(compand); - BufferRegion sourceRegion = source.PixelBuffer.GetRegion(sourceRectangle); + Buffer2DRegion sourceRegion = source.PixelBuffer.GetRegion(sourceRectangle); // To reintroduce parallel processing, we would launch multiple workers // for different row intervals of the image. diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs index 6cdb7934c0..96e516e39e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ResizeKernelMap horizontalKernelMap; - private readonly BufferRegion source; + private readonly Buffer2DRegion source; private readonly Rectangle sourceRectangle; @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public ResizeWorker( Configuration configuration, - BufferRegion source, + Buffer2DRegion source, PixelConversionModifiers conversionModifiers, ResizeKernelMap horizontalKernelMap, ResizeKernelMap verticalKernelMap, diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs index 0237c81705..20f3e0d566 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations private Buffer2D buffer; - private BufferRegion destRegion; + private Buffer2DRegion destRegion; [GlobalSetup] public void Setup() diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index 169b9c0fcd..169d3dd2dd 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20, AllocationOptions.Clean)) { - BufferRegion region = buffer.GetRegion(5, 10, 8, 8); + Buffer2DRegion region = buffer.GetRegion(5, 10, 8, 8); block.Copy1x1Scale(ref region.GetReferenceToOrigin(), region.Stride); Assert.Equal(block[0, 0], buffer[5, 10]); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100, AllocationOptions.Clean)) { - BufferRegion region = buffer.GetRegion(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); + Buffer2DRegion region = buffer.GetRegion(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); block.ScaledCopyTo(region, horizontalFactor, verticalFactor); for (int y = 0; y < 8 * verticalFactor; y++) diff --git a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs index 81173b456e..59f3f5aa04 100644 --- a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs +++ b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Memory { using Buffer2D buffer = this.memoryAllocator.Allocate2D(10, 20); var rectangle = new Rectangle(3, 2, 5, 6); - var area = new BufferRegion(buffer, rectangle); + var area = new Buffer2DRegion(buffer, rectangle); Assert.Equal(buffer, area.Buffer); Assert.Equal(rectangle, area.Rectangle); @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.Memory using Buffer2D buffer = this.CreateTestBuffer(20, 30); var r = new Rectangle(rx, ry, 5, 6); - BufferRegion region = buffer.GetRegion(r); + Buffer2DRegion region = buffer.GetRegion(r); int value = region[x, y]; int expected = ((ry + y) * 100) + rx + x; @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests.Memory using Buffer2D buffer = this.CreateTestBuffer(20, 30); var r = new Rectangle(rx, ry, w, h); - BufferRegion region = buffer.GetRegion(r); + Buffer2DRegion region = buffer.GetRegion(r); Span span = region.GetRowSpan(y); @@ -85,9 +85,9 @@ namespace SixLabors.ImageSharp.Tests.Memory public void GetSubArea() { using Buffer2D buffer = this.CreateTestBuffer(20, 30); - BufferRegion area0 = buffer.GetRegion(6, 8, 10, 10); + Buffer2DRegion area0 = buffer.GetRegion(6, 8, 10, 10); - BufferRegion area1 = area0.GetSubArea(4, 4, 5, 5); + Buffer2DRegion area1 = area0.GetSubRegion(4, 4, 5, 5); var expectedRect = new Rectangle(10, 12, 5, 5); @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Tests.Memory this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity; using Buffer2D buffer = this.CreateTestBuffer(20, 30); - BufferRegion area0 = buffer.GetRegion(6, 8, 10, 10); + Buffer2DRegion area0 = buffer.GetRegion(6, 8, 10, 10); ref int r = ref area0.GetReferenceToOrigin(); @@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.Tests.Memory this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity; using Buffer2D buffer = this.CreateTestBuffer(20, 30); - BufferRegion region = buffer.GetRegion(5, 5, 10, 10); + Buffer2DRegion region = buffer.GetRegion(5, 5, 10, 10); region.Clear(); Assert.NotEqual(0, buffer[4, 4]); diff --git a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs index 40eafc787a..2b81e721fb 100644 --- a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs +++ b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization using Image image = CreateTestImage(100, 100, 100); var strategy = new ExtensivePixelSamplingStrategy(); - foreach (BufferRegion region in strategy.EnumeratePixelRegions(image)) + foreach (Buffer2DRegion region in strategy.EnumeratePixelRegions(image)) { PaintWhite(region); } @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization var strategy = new DefaultPixelSamplingStrategy(maximumNumberOfPixels, 0.1); long visitedPixels = 0; - foreach (BufferRegion region in strategy.EnumeratePixelRegions(image)) + foreach (Buffer2DRegion region in strategy.EnumeratePixelRegions(image)) { PaintWhite(region); visitedPixels += region.Width * region.Height; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.True(visitRatio <= 1.1, $"{visitedPixels}>{maximumPixels}"); } - private static void PaintWhite(BufferRegion region) + private static void PaintWhite(Buffer2DRegion region) { var white = new L8(255); for (int y = 0; y < region.Height; y++) From 4e3dce1e95a57cd2a0636bbbd2784717ad994556 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 30 Apr 2020 22:05:44 +0100 Subject: [PATCH 198/213] Update source license info. --- .gitattributes | 1 + Directory.Build.props | 2 +- shared-infrastructure | 2 +- src/ImageSharp/Advanced/AdvancedImageExtensions.cs | 2 +- src/ImageSharp/Advanced/AotCompilerTools.cs | 2 +- src/ImageSharp/Advanced/IConfigurationProvider.cs | 2 +- src/ImageSharp/Advanced/IImageVisitor.cs | 2 +- src/ImageSharp/Advanced/IPixelSource.cs | 2 +- src/ImageSharp/Advanced/IRowIntervalOperation.cs | 2 +- src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs | 2 +- src/ImageSharp/Advanced/IRowOperation.cs | 2 +- src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs | 2 +- src/ImageSharp/Advanced/ParallelExecutionSettings.cs | 2 +- src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs | 2 +- src/ImageSharp/Advanced/ParallelRowIterator.cs | 2 +- src/ImageSharp/Color/Color.Conversions.cs | 2 +- src/ImageSharp/Color/Color.NamedColors.cs | 2 +- src/ImageSharp/Color/Color.WebSafePalette.cs | 2 +- src/ImageSharp/Color/Color.WernerPalette.cs | 2 +- src/ImageSharp/Color/Color.cs | 2 +- src/ImageSharp/ColorSpaces/CieLab.cs | 2 +- src/ImageSharp/ColorSpaces/CieLch.cs | 2 +- src/ImageSharp/ColorSpaces/CieLchuv.cs | 2 +- src/ImageSharp/ColorSpaces/CieLuv.cs | 2 +- src/ImageSharp/ColorSpaces/CieXyy.cs | 2 +- src/ImageSharp/ColorSpaces/CieXyz.cs | 2 +- src/ImageSharp/ColorSpaces/Cmyk.cs | 2 +- src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs | 2 +- src/ImageSharp/ColorSpaces/Companding/LCompanding.cs | 2 +- src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs | 2 +- src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs | 2 +- src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs | 2 +- src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs | 2 +- src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverterOptions.cs | 2 +- .../Conversion/Implementation/CieXyChromaticityCoordinates.cs | 2 +- .../Implementation/Converters/CIeLchToCieLabConverter.cs | 2 +- .../Implementation/Converters/CieLabToCieLchConverter.cs | 2 +- .../Implementation/Converters/CieLabToCieXyzConverter.cs | 2 +- .../Implementation/Converters/CieLchuvToCieLuvConverter.cs | 2 +- .../Implementation/Converters/CieLuvToCieLchuvConverter.cs | 2 +- .../Implementation/Converters/CieLuvToCieXyzConverter.cs | 2 +- .../Implementation/Converters/CieXyzAndCieXyyConverter.cs | 2 +- .../Converters/CieXyzAndHunterLabConverterBase.cs | 2 +- .../Implementation/Converters/CieXyzAndLmsConverter.cs | 2 +- .../Implementation/Converters/CieXyzToCieLabConverter.cs | 2 +- .../Implementation/Converters/CieXyzToCieLuvConverter.cs | 2 +- .../Implementation/Converters/CieXyzToHunterLabConverter.cs | 2 +- .../Implementation/Converters/CieXyzToLinearRgbConverter.cs | 2 +- .../Implementation/Converters/CmykAndRgbConverter.cs | 2 +- .../Implementation/Converters/HslAndRgbConverter.cs | 2 +- .../Implementation/Converters/HsvAndRgbConverter.cs | 2 +- .../Implementation/Converters/HunterLabToCieXyzConverter.cs | 2 +- .../Converters/LinearRgbAndCieXyzConverterBase.cs | 2 +- .../Implementation/Converters/LinearRgbToCieXyzConverter.cs | 2 +- .../Implementation/Converters/LinearRgbToRgbConverter.cs | 2 +- .../Implementation/Converters/RgbToLinearRgbConverter.cs | 2 +- .../Implementation/Converters/YCbCrAndRgbConverter.cs | 2 +- .../Conversion/Implementation/IChromaticAdaptation.cs | 2 +- .../Conversion/Implementation/LmsAdaptationMatrix.cs | 2 +- .../Implementation/RGBPrimariesChromaticityCoordinates.cs | 2 +- .../Conversion/Implementation/VonKriesChromaticAdaptation.cs | 2 +- .../Implementation/WorkingSpaces/GammaWorkingSpace.cs | 2 +- .../Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs | 2 +- .../Implementation/WorkingSpaces/Rec2020WorkingSpace.cs | 2 +- .../Implementation/WorkingSpaces/Rec709WorkingSpace.cs | 2 +- .../Implementation/WorkingSpaces/RgbWorkingSpace.cs | 2 +- .../Implementation/WorkingSpaces/SRgbWorkingSpace.cs | 2 +- src/ImageSharp/ColorSpaces/Hsl.cs | 2 +- src/ImageSharp/ColorSpaces/Hsv.cs | 2 +- src/ImageSharp/ColorSpaces/HunterLab.cs | 2 +- src/ImageSharp/ColorSpaces/Illuminants.cs | 2 +- src/ImageSharp/ColorSpaces/LinearRgb.cs | 2 +- src/ImageSharp/ColorSpaces/Lms.cs | 2 +- src/ImageSharp/ColorSpaces/Rgb.cs | 2 +- src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs | 2 +- src/ImageSharp/ColorSpaces/YCbCr.cs | 2 +- src/ImageSharp/Common/Constants.cs | 2 +- src/ImageSharp/Common/Exceptions/ImageFormatException.cs | 2 +- src/ImageSharp/Common/Exceptions/ImageProcessingException.cs | 2 +- .../Common/Exceptions/InvalidImageContentException.cs | 2 +- .../Common/Exceptions/UnknownImageFormatException.cs | 2 +- src/ImageSharp/Common/Extensions/ComparableExtensions.cs | 2 +- src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs | 2 +- src/ImageSharp/Common/Extensions/EncoderExtensions.cs | 2 +- src/ImageSharp/Common/Extensions/EnumerableExtensions.cs | 2 +- src/ImageSharp/Common/Extensions/StreamExtensions.cs | 2 +- src/ImageSharp/Common/Helpers/Buffer2DUtils.cs | 2 +- src/ImageSharp/Common/Helpers/DebugGuard.cs | 2 +- src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs | 2 +- src/ImageSharp/Common/Helpers/EnumUtils.cs | 2 +- src/ImageSharp/Common/Helpers/Guard.cs | 2 +- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- src/ImageSharp/Common/Helpers/InliningOptions.cs | 2 +- src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs | 2 +- src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs | 2 +- src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs | 2 +- .../Common/Helpers/SimdUtils.FallbackIntrinsics128.cs | 2 +- src/ImageSharp/Common/Helpers/SimdUtils.cs | 2 +- src/ImageSharp/Common/Helpers/TestHelpers.cs | 2 +- src/ImageSharp/Common/Helpers/TolerantMath.cs | 2 +- src/ImageSharp/Common/Helpers/UnitConverter.cs | 2 +- src/ImageSharp/Common/Helpers/Vector4Utilities.cs | 2 +- src/ImageSharp/Common/Tuples/Octet{T}.cs | 2 +- src/ImageSharp/Common/Tuples/Vector4Pair.cs | 2 +- src/ImageSharp/Configuration.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpArrayFileHeader.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpCompression.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpConstants.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpDecoder.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpEncoder.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpFileHeader.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpFileMarkerType.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpFormat.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpInfoHeaderType.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpMetadata.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs | 2 +- src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs | 2 +- src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Bmp/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/Bmp/MetadataExtensions.cs | 2 +- src/ImageSharp/Formats/Bmp/RleSkippedPixelHandling.cs | 2 +- src/ImageSharp/Formats/Gif/GifColorTableMode.cs | 2 +- src/ImageSharp/Formats/Gif/GifConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Gif/GifConstants.cs | 2 +- src/ImageSharp/Formats/Gif/GifDecoder.cs | 2 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifDisposalMethod.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoder.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifFormat.cs | 2 +- src/ImageSharp/Formats/Gif/GifFrameMetadata.cs | 2 +- src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetadata.cs | 2 +- src/ImageSharp/Formats/Gif/GifThrowHelper.cs | 2 +- src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs | 2 +- src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/Gif/LzwDecoder.cs | 2 +- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 2 +- src/ImageSharp/Formats/Gif/MetadataExtensions.cs | 2 +- .../Formats/Gif/Sections/GifGraphicControlExtension.cs | 2 +- src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs | 2 +- .../Formats/Gif/Sections/GifLogicalScreenDescriptor.cs | 2 +- .../Gif/Sections/GifNetscapeLoopingApplicationExtension.cs | 2 +- src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs | 2 +- src/ImageSharp/Formats/IImageDecoder.cs | 2 +- src/ImageSharp/Formats/IImageEncoder.cs | 2 +- src/ImageSharp/Formats/IImageFormat.cs | 2 +- src/ImageSharp/Formats/IImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/IImageInfoDetector.cs | 2 +- src/ImageSharp/Formats/ImageFormatManager.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt | 4 ++-- .../Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs | 2 +- .../ColorConverters/JpegColorConverter.FromGrayScale.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromRgb.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrBasic.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrSimd.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromYccK.cs | 2 +- .../Components/Decoder/ColorConverters/JpegColorConverter.cs | 2 +- .../Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs | 2 +- .../Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs | 2 +- .../Formats/Jpeg/Components/Decoder/HuffmanTable.cs | 2 +- .../Formats/Jpeg/Components/Decoder/IJpegComponent.cs | 2 +- .../Formats/Jpeg/Components/Decoder/IRawJpegData.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs | 2 +- .../Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs | 2 +- .../Formats/Jpeg/Components/Decoder/JpegColorSpace.cs | 2 +- .../Formats/Jpeg/Components/Decoder/JpegComponent.cs | 2 +- .../Jpeg/Components/Decoder/JpegComponentPostProcessor.cs | 2 +- .../Formats/Jpeg/Components/Decoder/JpegFileMarker.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs | 2 +- .../Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs | 2 +- .../Formats/Jpeg/Components/Decoder/ProfileResolver.cs | 2 +- .../Formats/Jpeg/Components/Decoder/QualityEvaluator.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs | 2 +- .../Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs | 2 +- .../Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs | 2 +- .../Formats/Jpeg/Components/FastFloatingPointDCT.cs | 2 +- .../Formats/Jpeg/Components/GenericBlock8x8.Generated.cs | 2 +- .../Formats/Jpeg/Components/GenericBlock8x8.Generated.tt | 4 ++-- src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs | 2 +- src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs | 2 +- src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs | 2 +- src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Jpeg/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegConstants.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegDecoder.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegEncoder.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegFormat.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegMetadata.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegSubsample.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs | 2 +- src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs | 2 +- src/ImageSharp/Formats/PixelTypeInfo.cs | 2 +- src/ImageSharp/Formats/Png/Adam7.cs | 2 +- src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs | 2 +- src/ImageSharp/Formats/Png/Filters/AverageFilter.cs | 2 +- src/ImageSharp/Formats/Png/Filters/FilterType.cs | 2 +- src/ImageSharp/Formats/Png/Filters/NoneFilter.cs | 2 +- src/ImageSharp/Formats/Png/Filters/PaethFilter.cs | 2 +- src/ImageSharp/Formats/Png/Filters/SubFilter.cs | 2 +- src/ImageSharp/Formats/Png/Filters/UpFilter.cs | 2 +- src/ImageSharp/Formats/Png/IPngDecoderOptions.cs | 2 +- src/ImageSharp/Formats/Png/IPngEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Png/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/Png/MetadataExtensions.cs | 2 +- src/ImageSharp/Formats/Png/PngBitDepth.cs | 2 +- src/ImageSharp/Formats/Png/PngChunk.cs | 2 +- src/ImageSharp/Formats/Png/PngChunkType.cs | 2 +- src/ImageSharp/Formats/Png/PngColorType.cs | 2 +- src/ImageSharp/Formats/Png/PngCompressionLevel.cs | 2 +- src/ImageSharp/Formats/Png/PngConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Png/PngConstants.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoder.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoder.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderHelpers.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs | 2 +- src/ImageSharp/Formats/Png/PngFilterMethod.cs | 2 +- src/ImageSharp/Formats/Png/PngFormat.cs | 2 +- src/ImageSharp/Formats/Png/PngHeader.cs | 2 +- src/ImageSharp/Formats/Png/PngImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Png/PngInterlaceMode.cs | 2 +- src/ImageSharp/Formats/Png/PngMetadata.cs | 2 +- src/ImageSharp/Formats/Png/PngScanlineProcessor.cs | 2 +- src/ImageSharp/Formats/Png/PngTextData.cs | 2 +- src/ImageSharp/Formats/Png/PngThrowHelper.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/Adler32.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/Crc32.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/DeflateThrowHelper.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/Deflater.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/DeflaterOutputStream.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/IChecksum.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs | 2 +- src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs | 2 +- src/ImageSharp/Formats/Tga/ITgaEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Tga/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/Tga/MetadataExtensions.cs | 2 +- src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs | 2 +- src/ImageSharp/Formats/Tga/TgaCompression.cs | 2 +- src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs | 2 +- src/ImageSharp/Formats/Tga/TgaConstants.cs | 2 +- src/ImageSharp/Formats/Tga/TgaDecoder.cs | 2 +- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 2 +- src/ImageSharp/Formats/Tga/TgaEncoder.cs | 2 +- src/ImageSharp/Formats/Tga/TgaEncoderCore.cs | 2 +- src/ImageSharp/Formats/Tga/TgaFileHeader.cs | 2 +- src/ImageSharp/Formats/Tga/TgaFormat.cs | 2 +- src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Tga/TgaImageOrigin.cs | 2 +- src/ImageSharp/Formats/Tga/TgaImageType.cs | 2 +- src/ImageSharp/Formats/Tga/TgaImageTypeExtensions.cs | 2 +- src/ImageSharp/Formats/Tga/TgaMetadata.cs | 2 +- src/ImageSharp/Formats/Tga/TgaThrowHelper.cs | 2 +- src/ImageSharp/GeometryUtilities.cs | 2 +- src/ImageSharp/GraphicOptionsDefaultsExtensions.cs | 2 +- src/ImageSharp/GraphicsOptions.cs | 2 +- src/ImageSharp/IConfigurationModule.cs | 2 +- src/ImageSharp/IDeepCloneable.cs | 2 +- src/ImageSharp/IImage.cs | 2 +- src/ImageSharp/IImageInfo.cs | 2 +- src/ImageSharp/IO/DoubleBufferedStreamReader.cs | 2 +- src/ImageSharp/IO/IFileSystem.cs | 2 +- src/ImageSharp/IO/LocalFileSystem.cs | 2 +- src/ImageSharp/Image.Decode.cs | 2 +- src/ImageSharp/Image.FromBytes.cs | 2 +- src/ImageSharp/Image.FromFile.cs | 2 +- src/ImageSharp/Image.FromStream.cs | 2 +- src/ImageSharp/Image.LoadPixelData.cs | 2 +- src/ImageSharp/Image.WrapMemory.cs | 2 +- src/ImageSharp/Image.cs | 2 +- src/ImageSharp/ImageExtensions.Internal.cs | 2 +- src/ImageSharp/ImageExtensions.cs | 2 +- src/ImageSharp/ImageFrame.LoadPixelData.cs | 2 +- src/ImageSharp/ImageFrame.cs | 2 +- src/ImageSharp/ImageFrameCollection.cs | 2 +- src/ImageSharp/ImageFrameCollection{TPixel}.cs | 2 +- src/ImageSharp/ImageFrame{TPixel}.cs | 2 +- src/ImageSharp/ImageInfo.cs | 2 +- src/ImageSharp/ImageInfoExtensions.cs | 2 +- src/ImageSharp/Image{TPixel}.cs | 2 +- src/ImageSharp/IndexedImageFrame{TPixel}.cs | 2 +- src/ImageSharp/Memory/Allocators/AllocationOptions.cs | 2 +- .../Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs | 2 +- .../ArrayPoolMemoryAllocator.CommonFactoryMethods.cs | 2 +- src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs | 2 +- src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs | 2 +- .../Memory/Allocators/Internals/BasicArrayBuffer.cs | 2 +- src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs | 2 +- .../Memory/Allocators/Internals/ManagedBufferBase.cs | 2 +- src/ImageSharp/Memory/Allocators/MemoryAllocator.cs | 2 +- src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs | 2 +- src/ImageSharp/Memory/Buffer2DExtensions.cs | 2 +- src/ImageSharp/Memory/Buffer2DRegion{T}.cs | 2 +- src/ImageSharp/Memory/Buffer2D{T}.cs | 2 +- src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs | 2 +- src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs | 2 +- src/ImageSharp/Memory/InvalidMemoryOperationException.cs | 2 +- src/ImageSharp/Memory/MemoryAllocatorExtensions.cs | 2 +- src/ImageSharp/Memory/MemoryOwnerExtensions.cs | 2 +- src/ImageSharp/Memory/RowInterval.cs | 2 +- src/ImageSharp/Memory/TransformItemsDelegate{T}.cs | 2 +- src/ImageSharp/Memory/TransformItemsInplaceDelegate.cs | 2 +- src/ImageSharp/Metadata/FrameDecodingMode.cs | 2 +- src/ImageSharp/Metadata/ImageFrameMetadata.cs | 2 +- src/ImageSharp/Metadata/ImageMetadata.cs | 2 +- src/ImageSharp/Metadata/PixelResolutionUnit.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 2 +- .../Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs | 2 +- .../Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs | 2 +- .../Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs | 2 +- .../Profiles/Exif/Values/ExifArrayValue{TValueType}.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifDoubleArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifFloatArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifNumberArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifRationalArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifShortArray.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifSignedByte.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifSignedLong.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifSignedRational.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifSignedRationalArray.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifSignedShort.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifString.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifValue{TValueType}.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs | 2 +- .../Metadata/Profiles/Exif/Values/IExifValue{TValueType}.cs | 2 +- .../Metadata/Profiles/ICC/Curves/IccCurveSegment.cs | 2 +- .../Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs | 2 +- .../Metadata/Profiles/ICC/Curves/IccOneDimensionalCurve.cs | 2 +- .../Metadata/Profiles/ICC/Curves/IccParametricCurve.cs | 2 +- .../Metadata/Profiles/ICC/Curves/IccResponseCurve.cs | 2 +- .../Metadata/Profiles/ICC/Curves/IccSampledCurveElement.cs | 2 +- .../Metadata/Profiles/ICC/DataReader/IccDataReader.Curves.cs | 2 +- .../Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs | 2 +- .../Metadata/Profiles/ICC/DataReader/IccDataReader.Matrix.cs | 2 +- .../ICC/DataReader/IccDataReader.MultiProcessElement.cs | 2 +- .../Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs | 2 +- .../Profiles/ICC/DataReader/IccDataReader.Primitives.cs | 2 +- .../Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs | 2 +- .../Metadata/Profiles/ICC/DataReader/IccDataReader.cs | 2 +- .../Metadata/Profiles/ICC/DataWriter/IccDataWriter.Curves.cs | 2 +- .../Metadata/Profiles/ICC/DataWriter/IccDataWriter.Lut.cs | 2 +- .../Metadata/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs | 2 +- .../ICC/DataWriter/IccDataWriter.MultiProcessElement.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs | 2 +- .../Metadata/Profiles/ICC/DataWriter/IccDataWriter.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Enums/IccClutDataType.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccColorSpaceType.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccColorantEncoding.cs | 2 +- .../Profiles/ICC/Enums/IccCurveMeasurementEncodings.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccCurveSegmentSignature.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccDeviceAttribute.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccFormulaCurveType.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccMeasurementGeometry.cs | 2 +- .../Profiles/ICC/Enums/IccMultiProcessElementSignature.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccParametricCurveType.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccPrimaryPlatformType.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileClass.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileFlag.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileTag.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccRenderingIntent.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccScreeningFlag.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccScreeningSpotType.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccSignatureName.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccStandardIlluminant.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccStandardObserver.cs | 2 +- .../Metadata/Profiles/ICC/Enums/IccTypeSignature.cs | 2 +- .../Profiles/ICC/Exceptions/InvalidIccProfileException.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/IccProfileHeader.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs | 2 +- .../ICC/MultiProcessElements/IccBAcsProcessElement.cs | 2 +- .../ICC/MultiProcessElements/IccClutProcessElement.cs | 2 +- .../ICC/MultiProcessElements/IccCurveSetProcessElement.cs | 2 +- .../ICC/MultiProcessElements/IccEAcsProcessElement.cs | 2 +- .../ICC/MultiProcessElements/IccMatrixProcessElement.cs | 2 +- .../ICC/MultiProcessElements/IccMultiProcessElement.cs | 2 +- .../ICC/TagDataEntries/IccChromaticityTagDataEntry.cs | 2 +- .../ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs | 2 +- .../ICC/TagDataEntries/IccColorantTableTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs | 2 +- .../TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs | 2 +- .../ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccNamedColor2TagDataEntry.cs | 2 +- .../ICC/TagDataEntries/IccParametricCurveTagDataEntry.cs | 2 +- .../ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs | 2 +- .../IccProfileSequenceIdentifierTagDataEntry.cs | 2 +- .../ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs | 2 +- .../ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs | 2 +- .../ICC/TagDataEntries/IccViewingConditionsTagDataEntry.cs | 2 +- .../Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs | 2 +- .../Metadata/Profiles/ICC/Various/IccColorantTableEntry.cs | 2 +- .../Metadata/Profiles/ICC/Various/IccLocalizedString.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Various/IccLut.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Various/IccNamedColor.cs | 2 +- .../Metadata/Profiles/ICC/Various/IccPositionNumber.cs | 2 +- .../Metadata/Profiles/ICC/Various/IccProfileDescription.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs | 2 +- .../Profiles/ICC/Various/IccProfileSequenceIdentifier.cs | 2 +- .../Metadata/Profiles/ICC/Various/IccResponseNumber.cs | 2 +- .../Metadata/Profiles/ICC/Various/IccScreeningChannel.cs | 2 +- .../Metadata/Profiles/ICC/Various/IccTagTableEntry.cs | 2 +- src/ImageSharp/Metadata/Profiles/ICC/Various/IccVersion.cs | 2 +- src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs | 2 +- src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs | 2 +- src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs | 2 +- src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs | 2 +- src/ImageSharp/PixelFormats/HalfTypeHelper.cs | 2 +- src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs | 2 +- src/ImageSharp/PixelFormats/IPixel.cs | 2 +- src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs | 2 +- .../PixelBlenders/DefaultPixelBlenders.Generated.cs | 2 +- .../PixelBlenders/DefaultPixelBlenders.Generated.tt | 4 ++-- .../PixelBlenders/PorterDuffFunctions.Generated.cs | 2 +- .../PixelBlenders/PorterDuffFunctions.Generated.tt | 4 ++-- .../PixelFormats/PixelBlenders/PorterDuffFunctions.cs | 2 +- src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs | 2 +- src/ImageSharp/PixelFormats/PixelColorBlendingMode.cs | 2 +- src/ImageSharp/PixelFormats/PixelConversionModifiers.cs | 2 +- .../PixelFormats/PixelConversionModifiersExtensions.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/A8.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs | 2 +- .../Generated/Argb32.PixelOperations.Generated.cs | 2 +- .../Generated/Bgr24.PixelOperations.Generated.cs | 2 +- .../Generated/Bgra32.PixelOperations.Generated.cs | 2 +- .../Generated/Bgra5551.PixelOperations.Generated.cs | 2 +- .../Generated/L16.PixelOperations.Generated.cs | 2 +- .../Generated/L8.PixelOperations.Generated.cs | 2 +- .../Generated/La16.PixelOperations.Generated.cs | 2 +- .../Generated/La32.PixelOperations.Generated.cs | 2 +- .../Generated/Rgb24.PixelOperations.Generated.cs | 2 +- .../Generated/Rgb48.PixelOperations.Generated.cs | 2 +- .../Generated/Rgba32.PixelOperations.Generated.cs | 2 +- .../Generated/Rgba64.PixelOperations.Generated.cs | 2 +- .../PixelImplementations/Generated/_Common.ttinclude | 2 +- .../PixelFormats/PixelImplementations/HalfSingle.cs | 2 +- .../PixelFormats/PixelImplementations/HalfVector2.cs | 2 +- .../PixelFormats/PixelImplementations/HalfVector4.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/L16.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/L8.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/La16.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/La32.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedByte2.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedByte4.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedShort2.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedShort4.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs | 2 +- .../PixelFormats/PixelImplementations/Rgba1010102.cs | 2 +- .../PixelImplementations/Rgba32.PixelOperations.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs | 2 +- .../PixelImplementations/RgbaVector.PixelOperations.cs | 2 +- .../PixelFormats/PixelImplementations/RgbaVector.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs | 2 +- .../PixelFormats/PixelOperations{TPixel}.Generated.cs | 2 +- .../PixelFormats/PixelOperations{TPixel}.Generated.tt | 4 ++-- .../PixelFormats/PixelOperations{TPixel}.PixelBenders.cs | 2 +- src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs | 2 +- src/ImageSharp/PixelFormats/RgbaComponent.cs | 2 +- src/ImageSharp/PixelFormats/Utils/PixelConverter.cs | 2 +- .../PixelFormats/Utils/Vector4Converters.Default.cs | 2 +- .../PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs | 2 +- src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs | 2 +- src/ImageSharp/Primitives/ColorMatrix.cs | 2 +- src/ImageSharp/Primitives/Complex64.cs | 2 +- src/ImageSharp/Primitives/ComplexVector4.cs | 2 +- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 2 +- src/ImageSharp/Primitives/LongRational.cs | 2 +- src/ImageSharp/Primitives/Matrix3x2Extensions.cs | 2 +- src/ImageSharp/Primitives/Number.cs | 2 +- src/ImageSharp/Primitives/Point.cs | 2 +- src/ImageSharp/Primitives/PointF.cs | 2 +- src/ImageSharp/Primitives/Rational.cs | 2 +- src/ImageSharp/Primitives/Rectangle.cs | 2 +- src/ImageSharp/Primitives/RectangleF.cs | 2 +- src/ImageSharp/Primitives/SignedRational.cs | 2 +- src/ImageSharp/Primitives/Size.cs | 2 +- src/ImageSharp/Primitives/SizeF.cs | 2 +- src/ImageSharp/Primitives/ValueSize.cs | 2 +- src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs | 2 +- src/ImageSharp/Processing/AffineTransformBuilder.cs | 2 +- src/ImageSharp/Processing/AnchorPositionMode.cs | 2 +- src/ImageSharp/Processing/ColorBlindnessMode.cs | 2 +- .../Processing/DefaultImageProcessorContext{TPixel}.cs | 2 +- src/ImageSharp/Processing/EdgeDetectionOperators.cs | 2 +- .../Extensions/Binarization/BinaryDitherExtensions.cs | 2 +- .../Extensions/Binarization/BinaryThresholdExtensions.cs | 2 +- .../Processing/Extensions/Convolution/BokehBlurExtensions.cs | 2 +- .../Processing/Extensions/Convolution/BoxBlurExtensions.cs | 2 +- .../Extensions/Convolution/DetectEdgesExtensions.cs | 2 +- .../Extensions/Convolution/GaussianBlurExtensions.cs | 2 +- .../Extensions/Convolution/GaussianSharpenExtensions.cs | 2 +- .../Processing/Extensions/Dithering/DitherExtensions.cs | 2 +- .../Processing/Extensions/Drawing/DrawImageExtensions.cs | 2 +- .../Processing/Extensions/Effects/OilPaintExtensions.cs | 2 +- .../Extensions/Effects/PixelRowDelegateExtensions.cs | 2 +- .../Processing/Extensions/Effects/PixelateExtensions.cs | 2 +- .../Processing/Extensions/Filters/BlackWhiteExtensions.cs | 2 +- .../Processing/Extensions/Filters/BrightnessExtensions.cs | 2 +- .../Processing/Extensions/Filters/ColorBlindnessExtensions.cs | 2 +- .../Processing/Extensions/Filters/ContrastExtensions.cs | 2 +- .../Processing/Extensions/Filters/FilterExtensions.cs | 2 +- .../Processing/Extensions/Filters/GrayscaleExtensions.cs | 2 +- src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs | 2 +- .../Processing/Extensions/Filters/InvertExtensions.cs | 2 +- .../Processing/Extensions/Filters/KodachromeExtensions.cs | 2 +- .../Processing/Extensions/Filters/LightnessExtensions.cs | 2 +- .../Processing/Extensions/Filters/LomographExtensions.cs | 2 +- .../Processing/Extensions/Filters/OpacityExtensions.cs | 2 +- .../Processing/Extensions/Filters/PolaroidExtensions.cs | 2 +- .../Processing/Extensions/Filters/SaturateExtensions.cs | 2 +- .../Processing/Extensions/Filters/SepiaExtensions.cs | 2 +- .../Normalization/HistogramEqualizationExtensions.cs | 2 +- .../Extensions/Overlays/BackgroundColorExtensions.cs | 2 +- .../Processing/Extensions/Overlays/GlowExtensions.cs | 2 +- .../Processing/Extensions/Overlays/VignetteExtensions.cs | 2 +- src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs | 2 +- .../Processing/Extensions/Quantization/QuantizeExtensions.cs | 2 +- .../Processing/Extensions/Transforms/AutoOrientExtensions.cs | 2 +- .../Processing/Extensions/Transforms/CropExtensions.cs | 2 +- .../Processing/Extensions/Transforms/EntropyCropExtensions.cs | 2 +- .../Processing/Extensions/Transforms/FlipExtensions.cs | 2 +- .../Processing/Extensions/Transforms/PadExtensions.cs | 2 +- .../Processing/Extensions/Transforms/ResizeExtensions.cs | 2 +- .../Processing/Extensions/Transforms/RotateExtensions.cs | 2 +- .../Processing/Extensions/Transforms/RotateFlipExtensions.cs | 2 +- .../Processing/Extensions/Transforms/SkewExtensions.cs | 2 +- .../Processing/Extensions/Transforms/TransformExtensions.cs | 2 +- src/ImageSharp/Processing/FlipMode.cs | 2 +- src/ImageSharp/Processing/GrayscaleMode.cs | 2 +- src/ImageSharp/Processing/IImageProcessingContext.cs | 2 +- src/ImageSharp/Processing/IImageProcessingContextFactory.cs | 2 +- .../Processing/IInternalImageProcessingContext{TPixel}.cs | 2 +- src/ImageSharp/Processing/KnownDitherings.cs | 2 +- src/ImageSharp/Processing/KnownFilterMatrices.cs | 2 +- src/ImageSharp/Processing/KnownQuantizers.cs | 2 +- src/ImageSharp/Processing/KnownResamplers.cs | 2 +- src/ImageSharp/Processing/OrientationMode.cs | 2 +- src/ImageSharp/Processing/PixelRowOperation.cs | 2 +- .../Processors/Binarization/AdaptiveThresholdProcessor.cs | 2 +- .../Binarization/AdaptiveThresholdProcessor{TPixel}.cs | 2 +- .../Processors/Binarization/BinaryThresholdProcessor.cs | 2 +- .../Binarization/BinaryThresholdProcessor{TPixel}.cs | 2 +- src/ImageSharp/Processing/Processors/CloningImageProcessor.cs | 2 +- .../Processing/Processors/CloningImageProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Convolution/BokehBlurProcessor.cs | 2 +- .../Processors/Convolution/BokehBlurProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Convolution/BoxBlurProcessor.cs | 2 +- .../Processors/Convolution/BoxBlurProcessor{TPixel}.cs | 2 +- .../Processors/Convolution/Convolution2DProcessor{TPixel}.cs | 2 +- .../Convolution/Convolution2PassProcessor{TPixel}.cs | 2 +- .../Processors/Convolution/ConvolutionProcessorHelpers.cs | 2 +- .../Processors/Convolution/ConvolutionProcessor{TPixel}.cs | 2 +- .../Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs | 2 +- .../Convolution/EdgeDetectorCompassProcessor{TPixel}.cs | 2 +- .../Processors/Convolution/EdgeDetectorProcessor.cs | 2 +- .../Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs | 2 +- .../Processors/Convolution/GaussianBlurProcessor.cs | 2 +- .../Processors/Convolution/GaussianBlurProcessor{TPixel}.cs | 2 +- .../Processors/Convolution/GaussianSharpenProcessor.cs | 2 +- .../Convolution/GaussianSharpenProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Convolution/KayyaliProcessor.cs | 2 +- .../Processors/Convolution/Kernels/CompassKernels.cs | 2 +- .../Processors/Convolution/Kernels/KayyaliKernels.cs | 2 +- .../Processors/Convolution/Kernels/KirschKernels.cs | 2 +- .../Processors/Convolution/Kernels/LaplacianKernelFactory.cs | 2 +- .../Processors/Convolution/Kernels/LaplacianKernels.cs | 2 +- .../Processors/Convolution/Kernels/PrewittKernels.cs | 2 +- .../Processors/Convolution/Kernels/RobertsCrossKernels.cs | 2 +- .../Processors/Convolution/Kernels/RobinsonKernels.cs | 2 +- .../Processors/Convolution/Kernels/ScharrKernels.cs | 2 +- .../Processing/Processors/Convolution/Kernels/SobelKernels.cs | 2 +- .../Processing/Processors/Convolution/KirschProcessor.cs | 2 +- .../Processors/Convolution/Laplacian3x3Processor.cs | 2 +- .../Processors/Convolution/Laplacian5x5Processor.cs | 2 +- .../Processors/Convolution/LaplacianOfGaussianProcessor.cs | 2 +- .../Processors/Convolution/Parameters/BokehBlurKernelData.cs | 2 +- .../Convolution/Parameters/BokehBlurKernelDataProvider.cs | 2 +- .../Processors/Convolution/Parameters/BokehBlurParameters.cs | 2 +- .../Processing/Processors/Convolution/PrewittProcessor.cs | 2 +- .../Processors/Convolution/RobertsCrossProcessor.cs | 2 +- .../Processing/Processors/Convolution/RobinsonProcessor.cs | 2 +- .../Processing/Processors/Convolution/ScharrProcessor.cs | 2 +- .../Processing/Processors/Convolution/SobelProcessor.cs | 2 +- .../Processing/Processors/Dithering/ErroDither.KnownTypes.cs | 2 +- src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs | 2 +- src/ImageSharp/Processing/Processors/Dithering/IDither.cs | 2 +- .../Dithering/IPaletteDitherImageProcessor{TPixel}.cs | 2 +- .../Processors/Dithering/OrderedDither.KnownTypes.cs | 2 +- .../Processing/Processors/Dithering/OrderedDither.cs | 2 +- .../Processing/Processors/Dithering/OrderedDitherFactory.cs | 2 +- .../Processing/Processors/Dithering/PaletteDitherProcessor.cs | 2 +- .../Processors/Dithering/PaletteDitherProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Drawing/DrawImageProcessor.cs | 2 +- .../Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs | 2 +- .../Processing/Processors/Effects/IPixelRowDelegate.cs | 2 +- .../Processing/Processors/Effects/OilPaintingProcessor.cs | 2 +- .../Processors/Effects/OilPaintingProcessor{TPixel}.cs | 2 +- .../Processors/Effects/PixelRowDelegateProcessor.cs | 2 +- .../Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs | 2 +- .../Processing/Processors/Effects/PixelateProcessor.cs | 2 +- .../Processors/Effects/PixelateProcessor{TPixel}.cs | 2 +- .../Effects/PositionAwarePixelRowDelegateProcessor.cs | 2 +- .../Processing/Processors/Filters/AchromatomalyProcessor.cs | 2 +- .../Processing/Processors/Filters/AchromatopsiaProcessor.cs | 2 +- .../Processing/Processors/Filters/BlackWhiteProcessor.cs | 2 +- .../Processing/Processors/Filters/BrightnessProcessor.cs | 2 +- .../Processing/Processors/Filters/ContrastProcessor.cs | 2 +- .../Processing/Processors/Filters/DeuteranomalyProcessor.cs | 2 +- .../Processing/Processors/Filters/DeuteranopiaProcessor.cs | 2 +- .../Processing/Processors/Filters/FilterProcessor.cs | 2 +- .../Processing/Processors/Filters/FilterProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Filters/GrayscaleBt601Processor.cs | 2 +- .../Processing/Processors/Filters/GrayscaleBt709Processor.cs | 2 +- src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs | 2 +- .../Processing/Processors/Filters/InvertProcessor.cs | 2 +- .../Processing/Processors/Filters/KodachromeProcessor.cs | 2 +- .../Processing/Processors/Filters/LightnessProcessor.cs | 2 +- .../Processing/Processors/Filters/LomographProcessor.cs | 2 +- .../Processors/Filters/LomographProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Filters/OpacityProcessor.cs | 2 +- .../Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Filters/PolaroidProcessor.cs | 2 +- .../Processors/Filters/PolaroidProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Filters/ProtanomalyProcessor.cs | 2 +- .../Processing/Processors/Filters/ProtanopiaProcessor.cs | 2 +- .../Processing/Processors/Filters/SaturateProcessor.cs | 2 +- .../Processing/Processors/Filters/SepiaProcessor.cs | 2 +- .../Processing/Processors/Filters/TritanomalyProcessor.cs | 2 +- .../Processing/Processors/Filters/TritanopiaProcessor.cs | 2 +- .../Processing/Processors/ICloningImageProcessor.cs | 2 +- .../Processing/Processors/ICloningImageProcessor{TPixel}.cs | 2 +- src/ImageSharp/Processing/Processors/IImageProcessor.cs | 2 +- .../Processing/Processors/IImageProcessor{TPixel}.cs | 2 +- .../Processing/Processors/ImageProcessorExtensions.cs | 2 +- .../Processing/Processors/ImageProcessor{TPixel}.cs | 2 +- .../Normalization/AdaptiveHistogramEqualizationProcessor.cs | 2 +- .../AdaptiveHistogramEqualizationProcessor{TPixel}.cs | 2 +- .../AdaptiveHistogramEqualizationSlidingWindowProcessor.cs | 2 +- ...tiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs | 2 +- .../Normalization/GlobalHistogramEqualizationProcessor.cs | 2 +- .../GlobalHistogramEqualizationProcessor{TPixel}.cs | 2 +- .../Processors/Normalization/HistogramEqualizationMethod.cs | 2 +- .../Processors/Normalization/HistogramEqualizationOptions.cs | 2 +- .../Normalization/HistogramEqualizationProcessor.cs | 2 +- .../Normalization/HistogramEqualizationProcessor{TPixel}.cs | 2 +- .../Processors/Overlays/BackgroundColorProcessor.cs | 2 +- .../Processors/Overlays/BackgroundColorProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Overlays/GlowProcessor.cs | 2 +- .../Processing/Processors/Overlays/GlowProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Overlays/VignetteProcessor.cs | 2 +- .../Processors/Overlays/VignetteProcessor{TPixel}.cs | 2 +- .../Processors/Quantization/DefaultPixelSamplingStrategy.cs | 2 +- .../Processors/Quantization/EuclideanPixelMap{TPixel}.cs | 2 +- .../Processors/Quantization/ExtensivePixelSamplingStrategy.cs | 2 +- .../Processors/Quantization/IPixelSamplingStrategy.cs | 2 +- .../Processing/Processors/Quantization/IQuantizer.cs | 2 +- .../Processing/Processors/Quantization/IQuantizer{TPixel}.cs | 2 +- .../Processing/Processors/Quantization/OctreeQuantizer.cs | 2 +- .../Processors/Quantization/OctreeQuantizer{TPixel}.cs | 2 +- .../Processing/Processors/Quantization/PaletteQuantizer.cs | 2 +- .../Processors/Quantization/PaletteQuantizer{TPixel}.cs | 2 +- .../Processing/Processors/Quantization/QuantizeProcessor.cs | 2 +- .../Processors/Quantization/QuantizeProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Quantization/QuantizerConstants.cs | 2 +- .../Processing/Processors/Quantization/QuantizerOptions.cs | 2 +- .../Processing/Processors/Quantization/QuantizerUtilities.cs | 2 +- .../Processors/Quantization/WebSafePaletteQuantizer.cs | 2 +- .../Processors/Quantization/WernerPaletteQuantizer.cs | 2 +- .../Processing/Processors/Quantization/WuQuantizer.cs | 2 +- .../Processing/Processors/Quantization/WuQuantizer{TPixel}.cs | 2 +- .../Processing/Processors/Transforms/CropProcessor.cs | 2 +- .../Processing/Processors/Transforms/CropProcessor{TPixel}.cs | 2 +- .../Processors/Transforms/DegenerateTransformException.cs | 2 +- .../Processing/Processors/Transforms/EntropyCropProcessor.cs | 2 +- .../Processors/Transforms/EntropyCropProcessor{TPixel}.cs | 2 +- src/ImageSharp/Processing/Processors/Transforms/IResampler.cs | 2 +- .../Transforms/IResamplingTransformImageProcessor{TPixel}.cs | 2 +- .../Processors/Transforms/Linear/AffineTransformProcessor.cs | 2 +- .../Transforms/Linear/AffineTransformProcessor{TPixel}.cs | 2 +- .../Processors/Transforms/Linear/AutoOrientProcessor.cs | 2 +- .../Transforms/Linear/AutoOrientProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Transforms/Linear/FlipProcessor.cs | 2 +- .../Processors/Transforms/Linear/FlipProcessor{TPixel}.cs | 2 +- .../Processors/Transforms/Linear/LinearTransformUtilities.cs | 2 +- .../Transforms/Linear/ProjectiveTransformProcessor.cs | 2 +- .../Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs | 2 +- .../Processors/Transforms/Linear/RotateProcessor.cs | 2 +- .../Processors/Transforms/Linear/RotateProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Transforms/Linear/SkewProcessor.cs | 2 +- .../Processors/Transforms/Resamplers/BicubicResampler.cs | 2 +- .../Processors/Transforms/Resamplers/BoxResampler.cs | 2 +- .../Processors/Transforms/Resamplers/CubicResampler.cs | 2 +- .../Processors/Transforms/Resamplers/LanczosResampler.cs | 2 +- .../Transforms/Resamplers/NearestNeighborResampler.cs | 2 +- .../Processors/Transforms/Resamplers/TriangleResampler.cs | 2 +- .../Processors/Transforms/Resamplers/WelchResampler.cs | 2 +- .../Processing/Processors/Transforms/Resize/ResizeHelper.cs | 2 +- .../Processing/Processors/Transforms/Resize/ResizeKernel.cs | 2 +- .../Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs | 2 +- .../Processors/Transforms/Resize/ResizeKernelMap.cs | 2 +- .../Processors/Transforms/Resize/ResizeProcessor.cs | 2 +- .../Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs | 2 +- .../Processing/Processors/Transforms/Resize/ResizeWorker.cs | 2 +- .../Processing/Processors/Transforms/TransformProcessor.cs | 2 +- .../Processors/Transforms/TransformProcessorHelpers.cs | 2 +- .../Processing/Processors/Transforms/TransformUtilities.cs | 2 +- src/ImageSharp/Processing/ProjectiveTransformBuilder.cs | 2 +- src/ImageSharp/Processing/ResizeMode.cs | 2 +- src/ImageSharp/Processing/ResizeOptions.cs | 2 +- src/ImageSharp/Processing/RotateMode.cs | 2 +- src/ImageSharp/Processing/TaperCorner.cs | 2 +- src/ImageSharp/Processing/TaperSide.cs | 2 +- src/ImageSharp/Properties/AssemblyInfo.cs | 2 +- src/ImageSharp/ReadOrigin.cs | 2 +- tests/ImageSharp.Benchmarks/BenchmarkBase.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs | 2 +- .../Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs | 2 +- .../Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs | 2 +- .../Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs | 2 +- .../Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs | 2 +- .../Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs | 2 +- .../Codecs/Jpeg/DecodeJpegParseStreamOnly.cs | 2 +- .../ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs | 2 +- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 2 +- .../Codecs/Jpeg/DoubleBufferedStreams.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs | 2 +- .../Codecs/Jpeg/LoadResizeSave_Aggregate.cs | 2 +- .../Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs | 2 +- .../ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs | 2 +- tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs | 2 +- tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs | 2 +- tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs | 2 +- tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs | 2 +- tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs | 2 +- tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs | 2 +- tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs | 2 +- tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs | 2 +- tests/ImageSharp.Benchmarks/Color/ColorEquality.cs | 2 +- .../Color/ColorspaceCieXyzToCieLabConvert.cs | 2 +- .../Color/ColorspaceCieXyzToHunterLabConvert.cs | 2 +- .../Color/ColorspaceCieXyzToLmsConvert.cs | 2 +- .../Color/ColorspaceCieXyzToRgbConvert.cs | 2 +- tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.LookupTables.cs | 2 +- tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs | 2 +- tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs | 2 +- tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs | 2 +- tests/ImageSharp.Benchmarks/Config.cs | 2 +- tests/ImageSharp.Benchmarks/General/Array2D.cs | 2 +- tests/ImageSharp.Benchmarks/General/ArrayReverse.cs | 2 +- tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs | 2 +- tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs | 2 +- .../General/BasicMath/ClampInt32IntoByte.cs | 2 +- tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs | 2 +- .../General/BasicMath/ModuloPowerOfTwoConstant.cs | 2 +- .../General/BasicMath/ModuloPowerOfTwoVariable.cs | 2 +- tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs | 2 +- tests/ImageSharp.Benchmarks/General/BasicMath/Round.cs | 2 +- tests/ImageSharp.Benchmarks/General/CopyBuffers.cs | 2 +- .../General/PixelConversion/ITestPixel.cs | 2 +- .../PixelConversion/PixelConversion_ConvertFromRgba32.cs | 2 +- .../PixelConversion/PixelConversion_ConvertFromVector4.cs | 2 +- .../PixelConversion/PixelConversion_ConvertToRgba32.cs | 2 +- ...elConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs | 2 +- .../PixelConversion/PixelConversion_ConvertToVector4.cs | 2 +- ...lConversion_ConvertToVector4_AsPartOfCompositeOperation.cs | 2 +- .../PixelConversion/PixelConversion_Rgba32_To_Argb32.cs | 2 +- .../PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs | 2 +- .../ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs | 2 +- .../ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs | 2 +- tests/ImageSharp.Benchmarks/General/StructCasting.cs | 2 +- tests/ImageSharp.Benchmarks/General/Vector4Constants.cs | 2 +- .../General/Vectorization/BitwiseOrUint32.cs | 2 +- tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs | 2 +- .../ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs | 2 +- tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs | 2 +- tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs | 2 +- .../ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs | 2 +- tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs | 2 +- .../General/Vectorization/Premultiply.cs | 2 +- .../General/Vectorization/ReinterpretUInt32AsFloat.cs | 2 +- .../General/Vectorization/SIMDBenchmarkBase.cs | 2 +- .../General/Vectorization/UInt32ToSingle.cs | 2 +- .../General/Vectorization/VectorFetching.cs | 2 +- .../General/Vectorization/WidenBytesToUInt32.cs | 2 +- .../PixelBlenders/PorterDuffBulkVsPixel.cs | 2 +- tests/ImageSharp.Benchmarks/Program.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Crop.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Resize.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Rotate.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Skew.cs | 2 +- tests/ImageSharp.Tests.ProfilingSandbox/Program.cs | 2 +- .../ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs | 2 +- tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs | 2 +- tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs | 2 +- tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs | 2 +- tests/ImageSharp.Tests/Color/ColorTests.cs | 2 +- tests/ImageSharp.Tests/Color/ReferencePalette.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs | 2 +- .../Colorspaces/CieXyChromaticityCoordinatesTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/CmykTests.cs | 2 +- .../Colorspaces/Companding/CompandingTests.cs | 2 +- .../Colorspaces/Conversion/ApproximateColorspaceComparer.cs | 2 +- .../Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs | 2 +- .../Conversion/CieLabAndCieLchuvConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLabAndCmykConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLabAndHslConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLabAndHsvConversionTests.cs | 2 +- .../Conversion/CieLabAndHunterLabConversionTests.cs | 2 +- .../Conversion/CieLabAndLinearRgbConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLabAndLmsConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLabAndRgbConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLchAndHslConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLchAndHsvConversionTests.cs | 2 +- .../Conversion/CieLchAndHunterLabConversionTests.cs | 2 +- .../Conversion/CieLchAndLinearRgbConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLchAndLmsConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLchAndRgbConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs | 2 +- .../Conversion/CieLchuvAndCieLchConversionTests.cs | 2 +- .../Conversion/CieLchuvAndCieLuvConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLuvAndHslConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs | 2 +- .../Conversion/CieLuvAndHunterLabConversionTests.cs | 2 +- .../Conversion/CieLuvAndLinearRgbConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieXyyAndHslConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs | 2 +- .../Conversion/CieXyyAndHunterLabConversionTests.cs | 2 +- .../Conversion/CieXyyAndLinearRgbConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs | 2 +- .../Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs | 2 +- .../Conversion/CieXyzAndCieLchuvConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs | 2 +- .../Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs | 2 +- .../Colorspaces/Conversion/CieXyzAndHslConversionTests.cs | 2 +- .../Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs | 2 +- .../Conversion/CieXyzAndHunterLabConversionTest.cs | 2 +- .../Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs | 2 +- .../Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs | 2 +- .../Colorspaces/Conversion/CmykAndCieLchConversionTests.cs | 2 +- .../Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs | 2 +- .../Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs | 2 +- .../Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs | 2 +- .../Colorspaces/Conversion/CmykAndHslConversionTests.cs | 2 +- .../Colorspaces/Conversion/CmykAndHsvConversionTests.cs | 2 +- .../Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs | 2 +- .../Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs | 2 +- .../Colorspaces/Conversion/ColorConverterAdaptTest.cs | 2 +- .../Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs | 2 +- .../Colorspaces/Conversion/RgbAndCmykConversionTest.cs | 2 +- .../Colorspaces/Conversion/RgbAndHslConversionTest.cs | 2 +- .../Colorspaces/Conversion/RgbAndHsvConversionTest.cs | 2 +- .../Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs | 2 +- .../Conversion/VonKriesChromaticAdaptationTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/HslTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/HsvTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/LmsTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/RgbTests.cs | 2 +- .../ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs | 2 +- tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs | 2 +- tests/ImageSharp.Tests/Common/ConstantsTests.cs | 2 +- tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs | 2 +- tests/ImageSharp.Tests/Common/SimdUtilsTests.cs | 2 +- tests/ImageSharp.Tests/Common/StreamExtensionsTests.cs | 2 +- tests/ImageSharp.Tests/Common/Tuple8.cs | 2 +- tests/ImageSharp.Tests/ConfigurationTests.cs | 2 +- tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs | 2 +- tests/ImageSharp.Tests/Drawing/DrawImageTests.cs | 2 +- tests/ImageSharp.Tests/FileTestBase.cs | 2 +- tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifFrameMetadataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs | 2 +- .../Formats/Gif/Sections/GifGraphicControlExtensionTests.cs | 2 +- .../Formats/Gif/Sections/GifImageDescriptorTests.cs | 2 +- .../Formats/Gif/Sections/GifLogicalScreenDescriptorTests.cs | 2 +- tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs | 2 +- .../Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs | 2 +- .../ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs | 2 +- .../ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs | 2 +- .../Formats/Jpg/JpegDecoderTests.Progressive.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegFileMarkerTests.cs | 2 +- .../Formats/Jpg/JpegImagePostProcessorTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs | 2 +- .../Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs | 2 +- .../Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs | 2 +- .../Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs | 2 +- .../Formats/Jpg/ReferenceImplementationsTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs | 2 +- .../Formats/Jpg/Utils/LibJpegTools.ComponentData.cs | 2 +- .../Formats/Jpg/Utils/LibJpegTools.SpectralData.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs | 2 +- .../Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs | 2 +- .../Utils/ReferenceImplementations.GT_FloatingPoint_DCT.cs | 2 +- .../Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs | 2 +- .../Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs | 2 +- .../Formats/Jpg/Utils/ReferenceImplementations.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/Utils/SpanExtensions.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngTextDataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs | 2 +- tests/ImageSharp.Tests/GlobalSuppressions.cs | 2 +- .../ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs | 2 +- tests/ImageSharp.Tests/GraphicsOptionsTests.cs | 2 +- tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs | 2 +- .../Helpers/ParallelExecutionSettingsTests.cs | 2 +- tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs | 2 +- tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs | 2 +- tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs | 2 +- tests/ImageSharp.Tests/Helpers/UnitConverterHelperTests.cs | 2 +- tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs | 2 +- tests/ImageSharp.Tests/IO/DoubleBufferedStreamReaderTests.cs | 2 +- tests/ImageSharp.Tests/IO/LocalFileSystemTests.cs | 2 +- tests/ImageSharp.Tests/Image/ImageCloneTests.cs | 2 +- .../Image/ImageFrameCollectionTests.Generic.cs | 2 +- .../Image/ImageFrameCollectionTests.NonGeneric.cs | 2 +- tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.cs | 2 +- tests/ImageSharp.Tests/Image/ImageFrameTests.cs | 2 +- tests/ImageSharp.Tests/Image/ImageRotationTests.cs | 2 +- tests/ImageSharp.Tests/Image/ImageSaveTests.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.Identify.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs | 2 +- .../ImageTests.Load_FileSystemPath_PassLocalConfiguration.cs | 2 +- .../ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs | 2 +- .../Image/ImageTests.Load_FromBytes_PassLocalConfiguration.cs | 2 +- .../Image/ImageTests.Load_FromBytes_UseGlobalConfiguration.cs | 2 +- .../ImageTests.Load_FromStream_PassLocalConfiguration.cs | 2 +- .../Image/ImageTests.Load_FromStream_ThrowsRightException.cs | 2 +- .../ImageTests.Load_FromStream_UseDefaultConfiguration.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.Save.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.cs | 2 +- tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs | 2 +- tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs | 2 +- tests/ImageSharp.Tests/Image/NoneSeekableStream.cs | 2 +- tests/ImageSharp.Tests/ImageInfoTests.cs | 2 +- tests/ImageSharp.Tests/Issues/Issue594.cs | 2 +- .../Memory/Allocators/ArrayPoolMemoryAllocatorTests.cs | 2 +- tests/ImageSharp.Tests/Memory/Allocators/BufferExtensions.cs | 2 +- tests/ImageSharp.Tests/Memory/Allocators/BufferTestSuite.cs | 2 +- .../Memory/Allocators/SimpleGcMemoryAllocatorTests.cs | 2 +- tests/ImageSharp.Tests/Memory/Buffer2DTests.cs | 2 +- tests/ImageSharp.Tests/Memory/BufferAreaTests.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupIndex.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupIndexTests.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupTests.CopyTo.cs | 2 +- .../MemoryGroupTests.SwapOrCopyContent.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupTests.View.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupTests.cs | 2 +- .../Memory/DiscontiguousBuffers/MemoryGroupTestsBase.cs | 2 +- tests/ImageSharp.Tests/Memory/TestStructs.cs | 2 +- tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs | 2 +- tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs | 2 +- .../Metadata/Profiles/Exif/ExifProfileTests.cs | 2 +- .../Metadata/Profiles/Exif/ExifReaderTests.cs | 2 +- .../Profiles/Exif/ExifTagDescriptionAttributeTests.cs | 2 +- .../ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs | 2 +- .../Metadata/Profiles/Exif/Values/ExifValuesTests.cs | 2 +- .../Profiles/ICC/DataReader/IccDataReaderCurvesTests.cs | 2 +- .../Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs | 2 +- .../Profiles/ICC/DataReader/IccDataReaderMatrixTests.cs | 2 +- .../ICC/DataReader/IccDataReaderMultiProcessElementTests.cs | 2 +- .../ICC/DataReader/IccDataReaderNonPrimitivesTests.cs | 2 +- .../Profiles/ICC/DataReader/IccDataReaderPrimitivesTests.cs | 2 +- .../Profiles/ICC/DataReader/IccDataReaderTagDataEntryTests.cs | 2 +- .../Metadata/Profiles/ICC/DataReader/IccDataReaderTests.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriterCurvesTests.cs | 2 +- .../Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriterLutTests1.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriterLutTests2.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriterMatrixTests.cs | 2 +- .../ICC/DataWriter/IccDataWriterMultiProcessElementTests.cs | 2 +- .../ICC/DataWriter/IccDataWriterNonPrimitivesTests.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriterPrimitivesTests.cs | 2 +- .../Profiles/ICC/DataWriter/IccDataWriterTagDataEntryTests.cs | 2 +- .../Metadata/Profiles/ICC/DataWriter/IccDataWriterTests.cs | 2 +- .../ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs | 2 +- .../ImageSharp.Tests/Metadata/Profiles/ICC/IccReaderTests.cs | 2 +- .../ImageSharp.Tests/Metadata/Profiles/ICC/IccWriterTests.cs | 2 +- .../Metadata/Profiles/ICC/Various/IccProfileIdTests.cs | 2 +- .../Metadata/Profiles/IPTC/IptcProfileTests.cs | 2 +- tests/ImageSharp.Tests/Numerics/RationalTests.cs | 2 +- tests/ImageSharp.Tests/Numerics/SignedRationalTests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/A8Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/L16Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/L8Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/La16Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/La32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs | 2 +- .../PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs | 2 +- .../PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs | 2 +- .../PixelBlenders/PorterDuffFunctionsTestsTPixel.cs | 2 +- .../PixelConverterTests.ReferenceImplementations.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs | 2 +- .../PixelConversionModifiersExtensionsTests.cs | 2 +- .../PixelOperationsTests.Argb32OperationsTests.cs | 2 +- .../PixelOperationsTests.Bgr24OperationsTests.cs | 2 +- .../PixelOperationsTests.Bgra32OperationsTests.cs | 2 +- .../PixelOperationsTests.Bgra5551OperationsTests.cs | 2 +- .../PixelOperationsTests.L16OperationsTests.cs | 2 +- .../PixelOperations/PixelOperationsTests.L8OperationsTests.cs | 2 +- .../PixelOperationsTests.La16OperationsTests.cs | 2 +- .../PixelOperationsTests.La32OperationsTests.cs | 2 +- .../PixelOperationsTests.Rgb24OperationsTests.cs | 2 +- .../PixelOperationsTests.Rgb48OperationsTests.cs | 2 +- .../PixelOperationsTests.Rgba32OperationsTests.cs | 2 +- .../PixelOperationsTests.Rgba64OperationsTests.cs | 2 +- .../PixelOperationsTests.RgbaVectorOperationsTests.cs | 2 +- .../PixelFormats/PixelOperations/PixelOperationsTests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs | 2 +- tests/ImageSharp.Tests/Primitives/ColorMatrixTests.cs | 2 +- tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs | 2 +- tests/ImageSharp.Tests/Primitives/PointFTests.cs | 2 +- tests/ImageSharp.Tests/Primitives/PointTests.cs | 2 +- tests/ImageSharp.Tests/Primitives/RectangleFTests.cs | 2 +- tests/ImageSharp.Tests/Primitives/RectangleTests.cs | 2 +- tests/ImageSharp.Tests/Primitives/SizeFTests.cs | 2 +- tests/ImageSharp.Tests/Primitives/SizeTests.cs | 2 +- .../Processing/BaseImageOperationsExtensionTest.cs | 2 +- .../Processing/Binarization/AdaptiveThresholdTests.cs | 2 +- .../Processing/Binarization/BinaryThresholdTest.cs | 2 +- .../Processing/Binarization/OrderedDitherFactoryTests.cs | 2 +- tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs | 2 +- .../Processing/Convolution/DetectEdgesTest.cs | 2 +- .../Processing/Convolution/GaussianBlurTest.cs | 2 +- .../Processing/Convolution/GaussianSharpenTest.cs | 2 +- .../Convolution/Processors/LaplacianKernelFactoryTests.cs | 2 +- tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs | 2 +- .../Processing/Effects/BackgroundColorTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs | 2 +- .../Processing/FakeImageOperationsProvider.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/BlackWhiteTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/BrightnessTest.cs | 2 +- .../ImageSharp.Tests/Processing/Filters/ColorBlindnessTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/FilterTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/GrayscaleTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/HueTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/InvertTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/KodachromeTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/LightnessTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/OpacityTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/SaturateTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Filters/SepiaTest.cs | 2 +- tests/ImageSharp.Tests/Processing/ImageOperationTests.cs | 2 +- .../Processing/ImageProcessingContextTests.cs | 2 +- .../Processing/Normalization/HistogramEqualizationTests.cs | 2 +- tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs | 2 +- .../Processing/Processors/Binarization/BinaryDitherTests.cs | 2 +- .../Processing/Processors/Binarization/BinaryThresholdTest.cs | 2 +- .../Processors/Convolution/Basic1ParameterConvolutionTests.cs | 2 +- .../Processing/Processors/Convolution/BokehBlurTest.cs | 2 +- .../Processing/Processors/Convolution/BoxBlurTest.cs | 2 +- .../Processing/Processors/Convolution/DetectEdgesTest.cs | 2 +- .../Processing/Processors/Convolution/GaussianBlurTest.cs | 2 +- .../Processing/Processors/Convolution/GaussianSharpenTest.cs | 2 +- .../Processing/Processors/Dithering/DitherTests.cs | 2 +- .../Processing/Processors/Effects/BackgroundColorTest.cs | 2 +- .../Processing/Processors/Effects/OilPaintTest.cs | 2 +- .../Processing/Processors/Effects/PixelShaderTest.cs | 2 +- .../Processing/Processors/Effects/PixelateTest.cs | 2 +- .../Processing/Processors/Filters/BlackWhiteTest.cs | 2 +- .../Processing/Processors/Filters/BrightnessTest.cs | 2 +- .../Processing/Processors/Filters/ColorBlindnessTest.cs | 2 +- .../Processing/Processors/Filters/ContrastTest.cs | 2 +- .../Processing/Processors/Filters/FilterTest.cs | 2 +- .../Processing/Processors/Filters/GrayscaleTest.cs | 2 +- .../ImageSharp.Tests/Processing/Processors/Filters/HueTest.cs | 2 +- .../Processing/Processors/Filters/InvertTest.cs | 2 +- .../Processing/Processors/Filters/KodachromeTest.cs | 2 +- .../Processing/Processors/Filters/LightnessTest.cs | 2 +- .../Processing/Processors/Filters/LomographTest.cs | 2 +- .../Processing/Processors/Filters/OpacityTest.cs | 2 +- .../Processing/Processors/Filters/PolaroidTest.cs | 2 +- .../Processing/Processors/Filters/SaturateTest.cs | 2 +- .../Processing/Processors/Filters/SepiaTest.cs | 2 +- .../Processing/Processors/Overlays/GlowTest.cs | 2 +- .../Processing/Processors/Overlays/OverlayTestBase.cs | 2 +- .../Processing/Processors/Overlays/VignetteTest.cs | 2 +- .../Processors/Quantization/OctreeQuantizerTests.cs | 2 +- .../Processors/Quantization/PaletteQuantizerTests.cs | 2 +- .../Processing/Processors/Quantization/QuantizerTests.cs | 2 +- .../Processing/Processors/Quantization/WuQuantizerTests.cs | 2 +- .../Processing/Processors/Transforms/AffineTransformTests.cs | 2 +- .../Processing/Processors/Transforms/AutoOrientTests.cs | 2 +- .../Processing/Processors/Transforms/CropTest.cs | 2 +- .../Processing/Processors/Transforms/EntropyCropTest.cs | 2 +- .../Processing/Processors/Transforms/FlipTests.cs | 2 +- .../Processing/Processors/Transforms/PadTest.cs | 2 +- .../Processing/Processors/Transforms/ResamplerTests.cs | 2 +- .../Processing/Processors/Transforms/ResizeHelperTests.cs | 2 +- .../Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs | 2 +- .../Processing/Processors/Transforms/ResizeKernelMapTests.cs | 2 +- .../Processing/Processors/Transforms/ResizeTests.cs | 2 +- .../Processing/Processors/Transforms/RotateFlipTests.cs | 2 +- .../Processing/Processors/Transforms/RotateTests.cs | 2 +- .../Processing/Processors/Transforms/SkewTests.cs | 2 +- .../Processing/Transforms/AffineTransformBuilderTests.cs | 2 +- .../ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs | 2 +- tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs | 2 +- .../ImageSharp.Tests/Processing/Transforms/EntropyCropTest.cs | 2 +- tests/ImageSharp.Tests/Processing/Transforms/FlipTests.cs | 2 +- tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs | 2 +- .../Processing/Transforms/ProjectiveTransformBuilderTests.cs | 2 +- .../Processing/Transforms/ProjectiveTransformTests.cs | 2 +- tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs | 2 +- .../ImageSharp.Tests/Processing/Transforms/RotateFlipTests.cs | 2 +- tests/ImageSharp.Tests/Processing/Transforms/RotateTests.cs | 2 +- tests/ImageSharp.Tests/Processing/Transforms/SkewTest.cs | 2 +- .../Processing/Transforms/TransformBuilderTestBase.cs | 2 +- .../Processing/Transforms/TransformsHelpersTest.cs | 2 +- .../ProfilingBenchmarks/JpegProfilingBenchmarks.cs | 2 +- .../ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs | 2 +- tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs | 2 +- .../ProfilingBenchmarks/ResizeProfilingBenchmarks.cs | 2 +- .../Quantization/PixelSamplingStrategyTests.cs | 2 +- tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs | 2 +- tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs | 2 +- tests/ImageSharp.Tests/TestDataIcc/IccTestDataArray.cs | 2 +- tests/ImageSharp.Tests/TestDataIcc/IccTestDataCurves.cs | 2 +- tests/ImageSharp.Tests/TestDataIcc/IccTestDataLut.cs | 2 +- tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs | 2 +- .../TestDataIcc/IccTestDataMultiProcessElements.cs | 2 +- .../ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs | 2 +- tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs | 2 +- tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs | 2 +- tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs | 2 +- tests/ImageSharp.Tests/TestFile.cs | 2 +- tests/ImageSharp.Tests/TestFileSystem.cs | 2 +- tests/ImageSharp.Tests/TestFontUtilities.cs | 2 +- tests/ImageSharp.Tests/TestFormat.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 2 +- .../TestUtilities/ApproximateFloatComparer.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/ArrayHelper.cs | 2 +- .../TestUtilities/Attributes/GroupOutputAttribute.cs | 2 +- .../TestUtilities/Attributes/ImageDataAttributeBase.cs | 2 +- .../Attributes/WithBasicTestPatternImagesAttribute.cs | 2 +- .../TestUtilities/Attributes/WithBlankImagesAttribute.cs | 2 +- .../TestUtilities/Attributes/WithFileAttribute.cs | 2 +- .../TestUtilities/Attributes/WithFileCollectionAttribute.cs | 2 +- .../TestUtilities/Attributes/WithMemberFactoryAttribute.cs | 2 +- .../Attributes/WithSolidFilledImagesAttribute.cs | 2 +- .../Attributes/WithTestPatternImagesAttribute.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs | 2 +- .../ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs | 2 +- .../TestUtilities/ImageComparison/ExactImageComparer.cs | 2 +- .../Exceptions/ImageDifferenceIsOverThresholdException.cs | 2 +- .../Exceptions/ImageDimensionsMismatchException.cs | 2 +- .../ImageComparison/Exceptions/ImagesSimilarityException.cs | 2 +- .../TestUtilities/ImageComparison/ImageComparer.cs | 2 +- .../TestUtilities/ImageComparison/ImageSimilarityReport.cs | 2 +- .../TestUtilities/ImageComparison/PixelDifference.cs | 2 +- .../TestUtilities/ImageComparison/TolerantImageComparer.cs | 2 +- .../TestUtilities/ImageProviders/BasicTestPatternProvider.cs | 2 +- .../TestUtilities/ImageProviders/BlankProvider.cs | 2 +- .../TestUtilities/ImageProviders/FileProvider.cs | 2 +- .../TestUtilities/ImageProviders/ITestImageProvider.cs | 2 +- .../TestUtilities/ImageProviders/MemberMethodProvider.cs | 2 +- .../TestUtilities/ImageProviders/SolidProvider.cs | 2 +- .../TestUtilities/ImageProviders/TestImageProvider.cs | 2 +- .../TestUtilities/ImageProviders/TestPatternProvider.cs | 2 +- .../ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/MeasureFixture.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs | 2 +- .../TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs | 2 +- .../TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs | 2 +- .../ReferenceCodecs/SystemDrawingReferenceDecoder.cs | 2 +- .../ReferenceCodecs/SystemDrawingReferenceEncoder.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs | 2 +- .../ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestPixel.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestType.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestUtils.cs | 2 +- tests/ImageSharp.Tests/TestUtilities/TestVector4.cs | 2 +- .../TestUtilities/Tests/BasicSerializerTests.cs | 2 +- .../ImageSharp.Tests/TestUtilities/Tests/GroupOutputTests.cs | 2 +- .../TestUtilities/Tests/ImageComparerTests.cs | 2 +- .../TestUtilities/Tests/MagickReferenceCodecTests.cs | 2 +- .../TestUtilities/Tests/ReferenceDecoderBenchmarks.cs | 2 +- .../TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs | 2 +- .../TestUtilities/Tests/TestEnvironmentTests.cs | 2 +- .../TestUtilities/Tests/TestImageExtensionsTests.cs | 2 +- .../TestUtilities/Tests/TestImageProviderTests.cs | 2 +- .../TestUtilities/Tests/TestUtilityExtensionsTests.cs | 2 +- tests/ImageSharp.Tests/VectorAssert.cs | 2 +- 1408 files changed, 1413 insertions(+), 1412 deletions(-) diff --git a/.gitattributes b/.gitattributes index 66aaca3738..3b7ad7e196 100644 --- a/.gitattributes +++ b/.gitattributes @@ -107,6 +107,7 @@ *.tga binary *.ttc binary *.ttf binary +*.webp binary *.woff binary *.woff2 binary *.xls binary diff --git a/Directory.Build.props b/Directory.Build.props index b5f5f1279e..4e79fa187e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -126,7 +126,7 @@ - + diff --git a/shared-infrastructure b/shared-infrastructure index ea561c249b..44686c6a11 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit ea561c249ba86352fe3b69e612b8072f3652eacb +Subproject commit 44686c6a116961f4a5163e19a0d6136e1b0b9f72 diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index a79733fec3..f4e9f30429 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index d692292b09..eaea7a971b 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics.CodeAnalysis; diff --git a/src/ImageSharp/Advanced/IConfigurationProvider.cs b/src/ImageSharp/Advanced/IConfigurationProvider.cs index d3e3a91aa3..2deb73a201 100644 --- a/src/ImageSharp/Advanced/IConfigurationProvider.cs +++ b/src/ImageSharp/Advanced/IConfigurationProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Advanced { diff --git a/src/ImageSharp/Advanced/IImageVisitor.cs b/src/ImageSharp/Advanced/IImageVisitor.cs index 079db42c07..50e6337e59 100644 --- a/src/ImageSharp/Advanced/IImageVisitor.cs +++ b/src/ImageSharp/Advanced/IImageVisitor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Advanced/IPixelSource.cs b/src/ImageSharp/Advanced/IPixelSource.cs index f609b15d30..f0b2687de6 100644 --- a/src/ImageSharp/Advanced/IPixelSource.cs +++ b/src/ImageSharp/Advanced/IPixelSource.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Advanced/IRowIntervalOperation.cs b/src/ImageSharp/Advanced/IRowIntervalOperation.cs index 980ed91a78..a044d8fade 100644 --- a/src/ImageSharp/Advanced/IRowIntervalOperation.cs +++ b/src/ImageSharp/Advanced/IRowIntervalOperation.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs b/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs index 47fcf253eb..f554e89203 100644 --- a/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs +++ b/src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Advanced/IRowOperation.cs b/src/ImageSharp/Advanced/IRowOperation.cs index 0a6065e4b1..eeec6dce39 100644 --- a/src/ImageSharp/Advanced/IRowOperation.cs +++ b/src/ImageSharp/Advanced/IRowOperation.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Advanced { diff --git a/src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs b/src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs index 7a13930fad..7d8250ddfc 100644 --- a/src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs +++ b/src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Advanced/ParallelExecutionSettings.cs b/src/ImageSharp/Advanced/ParallelExecutionSettings.cs index 54ee069184..4811893747 100644 --- a/src/ImageSharp/Advanced/ParallelExecutionSettings.cs +++ b/src/ImageSharp/Advanced/ParallelExecutionSettings.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Threading.Tasks; diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs index 3f0f77ca39..f8250632b6 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs index fb85de9863..45701f9331 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs index a6e0717f48..1d35b8a31e 100644 --- a/src/ImageSharp/Color/Color.Conversions.cs +++ b/src/ImageSharp/Color/Color.Conversions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Color/Color.NamedColors.cs b/src/ImageSharp/Color/Color.NamedColors.cs index 240ce304d8..49c18c9a51 100644 --- a/src/ImageSharp/Color/Color.NamedColors.cs +++ b/src/ImageSharp/Color/Color.NamedColors.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Color/Color.WebSafePalette.cs b/src/ImageSharp/Color/Color.WebSafePalette.cs index 8e5fb2a55b..67c6087301 100644 --- a/src/ImageSharp/Color/Color.WebSafePalette.cs +++ b/src/ImageSharp/Color/Color.WebSafePalette.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Color/Color.WernerPalette.cs b/src/ImageSharp/Color/Color.WernerPalette.cs index 2948b4c52c..f8bada44a5 100644 --- a/src/ImageSharp/Color/Color.WernerPalette.cs +++ b/src/ImageSharp/Color/Color.WernerPalette.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index e0f9d1e8d1..9056d023ae 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 146acf12ee..837812ad0a 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 99d4c09e97..52d53ffb2d 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index ab6f639a2b..58fcbfcc3e 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index d54d92b62a..183222f3d7 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index fff296945e..2dc4a62041 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index 6c5adcb219..f6c95b44bd 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index 5229cf14fb..8228c3050f 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs index 09b324b00f..73faa30fe9 100644 --- a/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs index 981e32f8ea..7898750a06 100644 --- a/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs index 773fe81647..fab8e655b2 100644 --- a/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs index edc0b9763f..0d2030d0d0 100644 --- a/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs index cc30c3632d..f5c61fe243 100644 --- a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs b/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs index 2bcdc5127f..5ce915e3eb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 2b9073814f..37aeae6bab 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 69d0c1bed3..1880d535ce 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 52f8724305..560cd763fa 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 2588561c84..337cccc668 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index 867b44a784..6625648631 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index 344b83254c..90654efe3c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 8362432ab9..70d6a0c7b8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 3ff9ac85fd..61534127ab 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 7c74363919..18ccfa054d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index e60ad5e20c..dbcba38cb7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index 91e5549ac8..9a9c9be78a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index b2c23b5a49..8801f837f1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index 3b8638f7d2..9b089b7c92 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index e83dcb1258..4695706d0a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 4ea1d8d8fb..83b756817e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index 05d3b2f2db..2c08db268b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs index 27dd989ade..bf77868756 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs index 1e774fe67a..6be996fbbf 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs index 014ca1abbd..b18bd81a64 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs index e1bf04aa76..3bf36efaf4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs index bafd0df47a..bd069373b6 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs index 2dae2669fb..1ccc59dc56 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs index 29fdae69c9..78e1c39f50 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs index 09040c98c6..b07dcafadb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs index f704d1a348..083259d64d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs index 68f6c495d4..47fddbf422 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs index a22b097d2b..5094c46ec6 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs index 4f4aa84820..42e468733f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs index 96ec96b49c..acce087fbd 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs index 881d3d9198..ed43951e31 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs index 25558537a9..999fef5fd4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs index 8e92ced949..6f2dafdf22 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs index 5dbd23b8b8..844bf6c888 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs index 04ab0480b4..9316db4913 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs index 795db7e2c9..e9c8e17a58 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs index 1058170758..e6d59e0a5c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs index adaad50fe0..25fbf80252 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs index 54081b6393..e5bde64777 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs index bc8c6f0301..7a50b67e36 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs index 0821c05c34..30eda8826d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs index 69877d8b55..e26ed0e90b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs index 8b8e4ab57a..1e3959db2b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs index 03378f431b..7ec9f27031 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs index 7589a1d570..0e01fd5bd0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs index c7020723be..6a2e451e9f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs index d9c4365270..2d97db2bce 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs index 4698534db4..c3f4e5fb98 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs index 80b635cadc..6c59fd3c31 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs index 2e5a5a4eb2..c112d118ec 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs index c9246f5100..7456c6c939 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Companding; diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 04b3bea41f..75ac8c0538 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index 8ccc74ae09..76ed552be9 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 402761d8c1..ca1d9eeefc 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Illuminants.cs b/src/ImageSharp/ColorSpaces/Illuminants.cs index d5c1b3eed5..de77f6eeea 100644 --- a/src/ImageSharp/ColorSpaces/Illuminants.cs +++ b/src/ImageSharp/ColorSpaces/Illuminants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.ColorSpaces { diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index c120ef1141..1351859982 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 0ee56abbc2..0718398c6e 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 3c26b77332..8d6db080a0 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs index 152c7ee0bc..ec6db8bb11 100644 --- a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs +++ b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.ColorSpaces.Conversion; diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index b0563bb899..3f5d631596 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Common/Constants.cs b/src/ImageSharp/Common/Constants.cs index a8a693fa67..57b1b904c3 100644 --- a/src/ImageSharp/Common/Constants.cs +++ b/src/ImageSharp/Common/Constants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp { diff --git a/src/ImageSharp/Common/Exceptions/ImageFormatException.cs b/src/ImageSharp/Common/Exceptions/ImageFormatException.cs index 4028b70b0e..25ed4b589d 100644 --- a/src/ImageSharp/Common/Exceptions/ImageFormatException.cs +++ b/src/ImageSharp/Common/Exceptions/ImageFormatException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs index ccd0b71e54..9e225b5c1a 100644 --- a/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs +++ b/src/ImageSharp/Common/Exceptions/ImageProcessingException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs b/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs index 8be13919f1..34d3c658dc 100644 --- a/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs +++ b/src/ImageSharp/Common/Exceptions/InvalidImageContentException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Common/Exceptions/UnknownImageFormatException.cs b/src/ImageSharp/Common/Exceptions/UnknownImageFormatException.cs index 82aa8cf09f..6936852e4a 100644 --- a/src/ImageSharp/Common/Exceptions/UnknownImageFormatException.cs +++ b/src/ImageSharp/Common/Exceptions/UnknownImageFormatException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp { diff --git a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs index 1fe2a24c77..e9dfc4bc98 100644 --- a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs b/src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs index 64532af274..66bd639723 100644 --- a/src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ConfigurationExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Threading.Tasks; diff --git a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs index 87aaa93a9f..17c72161f3 100644 --- a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs +++ b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #if !SUPPORTS_ENCODING_STRING using System; diff --git a/src/ImageSharp/Common/Extensions/EnumerableExtensions.cs b/src/ImageSharp/Common/Extensions/EnumerableExtensions.cs index 983a1eb8b3..2365bd86c3 100644 --- a/src/ImageSharp/Common/Extensions/EnumerableExtensions.cs +++ b/src/ImageSharp/Common/Extensions/EnumerableExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Common/Extensions/StreamExtensions.cs b/src/ImageSharp/Common/Extensions/StreamExtensions.cs index 5d86682571..1eff9d7e99 100644 --- a/src/ImageSharp/Common/Extensions/StreamExtensions.cs +++ b/src/ImageSharp/Common/Extensions/StreamExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Common/Helpers/Buffer2DUtils.cs b/src/ImageSharp/Common/Helpers/Buffer2DUtils.cs index 312ab388d7..d81c821efe 100644 --- a/src/ImageSharp/Common/Helpers/Buffer2DUtils.cs +++ b/src/ImageSharp/Common/Helpers/Buffer2DUtils.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs index 356dd419b5..f793e8165d 100644 --- a/src/ImageSharp/Common/Helpers/DebugGuard.cs +++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs index 462eeb3021..7febb3e9be 100644 --- a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs +++ b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Common/Helpers/EnumUtils.cs b/src/ImageSharp/Common/Helpers/EnumUtils.cs index a98b7f84c6..6dcfdb0ad1 100644 --- a/src/ImageSharp/Common/Helpers/EnumUtils.cs +++ b/src/ImageSharp/Common/Helpers/EnumUtils.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index 3ab1b199a6..1e6e971229 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Reflection; diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index fb1f88a2da..c88aaba768 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index 895b6250f6..d3600d4dda 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // Uncomment this for verbose profiler results. DO NOT PUSH TO MAIN! // #define PROFILING diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs index ea1ffba05a..96fbdf1241 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Avx2Intrinsics.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs index 1099678f76..da67143256 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 69d5dfa73a..7df12d5e29 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index f16c91b40d..3a9cf4631b 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 0dc45d887b..054dbed599 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/src/ImageSharp/Common/Helpers/TestHelpers.cs b/src/ImageSharp/Common/Helpers/TestHelpers.cs index c6574e4b58..d1da2def58 100644 --- a/src/ImageSharp/Common/Helpers/TestHelpers.cs +++ b/src/ImageSharp/Common/Helpers/TestHelpers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Common.Helpers { diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs index 62b5644725..0415ee1e97 100644 --- a/src/ImageSharp/Common/Helpers/TolerantMath.cs +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Common/Helpers/UnitConverter.cs b/src/ImageSharp/Common/Helpers/UnitConverter.cs index 9e43061702..b353e303ce 100644 --- a/src/ImageSharp/Common/Helpers/UnitConverter.cs +++ b/src/ImageSharp/Common/Helpers/UnitConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/Common/Helpers/Vector4Utilities.cs b/src/ImageSharp/Common/Helpers/Vector4Utilities.cs index 9fb4eb7909..eee8c49c6d 100644 --- a/src/ImageSharp/Common/Helpers/Vector4Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector4Utilities.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Common/Tuples/Octet{T}.cs b/src/ImageSharp/Common/Tuples/Octet{T}.cs index 71e7da801e..c0bec254a3 100644 --- a/src/ImageSharp/Common/Tuples/Octet{T}.cs +++ b/src/ImageSharp/Common/Tuples/Octet{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 1fdae0d5dd..123f838b39 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 17ac8c3fd8..1aeea3b7a2 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Bmp/BmpArrayFileHeader.cs b/src/ImageSharp/Formats/Bmp/BmpArrayFileHeader.cs index e8afb422a8..bc33dbb89c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpArrayFileHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpArrayFileHeader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs index 6e1145beb7..f126863e69 100644 --- a/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Bmp { diff --git a/src/ImageSharp/Formats/Bmp/BmpCompression.cs b/src/ImageSharp/Formats/Bmp/BmpCompression.cs index 81a76e28d1..2381a501de 100644 --- a/src/ImageSharp/Formats/Bmp/BmpCompression.cs +++ b/src/ImageSharp/Formats/Bmp/BmpCompression.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Bmp { diff --git a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs index 57117cc075..ff6782f09c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Bmp { diff --git a/src/ImageSharp/Formats/Bmp/BmpConstants.cs b/src/ImageSharp/Formats/Bmp/BmpConstants.cs index 5cbed4af2b..be577556da 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConstants.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs index cafe101060..6547fe76a7 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index eeb1ae714a..0661f31456 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index 9c05ae2d50..fbc94a73f5 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Advanced; diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 2d6b623a18..cc07c4d871 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs index 16421cfb0c..784e6393e9 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Bmp/BmpFileMarkerType.cs b/src/ImageSharp/Formats/Bmp/BmpFileMarkerType.cs index 4abcaa3a08..0ad0030372 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFileMarkerType.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFileMarkerType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Bmp { diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs index 056fbe8406..36ae5e10ba 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs index e1fc9ef1fe..dce32ace9a 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs index 3411de0421..0c4289b327 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Bmp/BmpInfoHeaderType.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeaderType.cs index a92a19d9ba..d4880fd40c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpInfoHeaderType.cs +++ b/src/ImageSharp/Formats/Bmp/BmpInfoHeaderType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Bmp { diff --git a/src/ImageSharp/Formats/Bmp/BmpMetadata.cs b/src/ImageSharp/Formats/Bmp/BmpMetadata.cs index 83d4eefe40..396806d22c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetadata.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Bmp { diff --git a/src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs b/src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs index c48566f835..900c788724 100644 --- a/src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs +++ b/src/ImageSharp/Formats/Bmp/BmpThrowHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs index f456f2ba3a..bf25600675 100644 --- a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs +++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Bmp { diff --git a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs index 59ad929df7..4bbf5b87b1 100644 --- a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs +++ b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Quantization; diff --git a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs index 0c37907c22..cfbac8e4e4 100644 --- a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs b/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs index 0315b3c768..c50545e885 100644 --- a/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Bmp/MetadataExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/Formats/Bmp/RleSkippedPixelHandling.cs b/src/ImageSharp/Formats/Bmp/RleSkippedPixelHandling.cs index 493fe366ad..3641c7fe8c 100644 --- a/src/ImageSharp/Formats/Bmp/RleSkippedPixelHandling.cs +++ b/src/ImageSharp/Formats/Bmp/RleSkippedPixelHandling.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Bmp { diff --git a/src/ImageSharp/Formats/Gif/GifColorTableMode.cs b/src/ImageSharp/Formats/Gif/GifColorTableMode.cs index 95b3335626..68f084de42 100644 --- a/src/ImageSharp/Formats/Gif/GifColorTableMode.cs +++ b/src/ImageSharp/Formats/Gif/GifColorTableMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Gif { diff --git a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs index 861d3e0368..4656629b9b 100644 --- a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs +++ b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Gif { diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index 06c4b3fc6e..410164fbc4 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 553163bd7e..faa2498d14 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 2d8bd319d7..81aa556956 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs b/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs index 982340db66..872ab3360b 100644 --- a/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs +++ b/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Gif { diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index e95a1ae32d..762fc03fce 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Advanced; diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 0f20630601..34c92a180c 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs index abe87819c6..e3122c96e7 100644 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs b/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs index dfc96af5a6..530e368efe 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Gif { diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs index b8f9a03f1a..735be07d9b 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Gif/GifMetadata.cs b/src/ImageSharp/Formats/Gif/GifMetadata.cs index 5fe86c4dd3..1a1e90fe61 100644 --- a/src/ImageSharp/Formats/Gif/GifMetadata.cs +++ b/src/ImageSharp/Formats/Gif/GifMetadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Gif/GifThrowHelper.cs b/src/ImageSharp/Formats/Gif/GifThrowHelper.cs index 1b20c9f64c..dd189ae036 100644 --- a/src/ImageSharp/Formats/Gif/GifThrowHelper.cs +++ b/src/ImageSharp/Formats/Gif/GifThrowHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs index 050ab170b2..5bd530bba1 100644 --- a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs index 151e1a23d6..cdb6c72608 100644 --- a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index c7ac001ff5..cc08976e2e 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs index 8289ee75b0..337118a5d2 100644 --- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index 516b82396d..004c3cb209 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index 7c432d26fe..a504ffdf58 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs index cb548d687d..e5a8b8eba3 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs index c3504dfe7b..c7cdb44ad0 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs index 1cfec4763a..71a661a661 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs index 5e26370bae..251f262b7c 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs b/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs index c8bd286746..efeb0e6020 100644 --- a/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs +++ b/src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index 7a7fc4b263..4f17f67292 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Formats/IImageEncoder.cs b/src/ImageSharp/Formats/IImageEncoder.cs index d5ff4b93c4..01478eb3e3 100644 --- a/src/ImageSharp/Formats/IImageEncoder.cs +++ b/src/ImageSharp/Formats/IImageEncoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index bd0d6357cb..de49afffb7 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/IImageFormatDetector.cs b/src/ImageSharp/Formats/IImageFormatDetector.cs index becd8200cf..8d5f0677f5 100644 --- a/src/ImageSharp/Formats/IImageFormatDetector.cs +++ b/src/ImageSharp/Formats/IImageFormatDetector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/IImageInfoDetector.cs b/src/ImageSharp/Formats/IImageInfoDetector.cs index b7769e8955..2bd33c6164 100644 --- a/src/ImageSharp/Formats/IImageInfoDetector.cs +++ b/src/ImageSharp/Formats/IImageInfoDetector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs index e341557068..f4f4c1b103 100644 --- a/src/ImageSharp/Formats/ImageFormatManager.cs +++ b/src/ImageSharp/Formats/ImageFormatManager.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Concurrent; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs index acde84c912..0879aaaeb4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index 8e14ed2c36..5fe2b3ba34 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index a1a6b01726..7a7f35e30c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -1,6 +1,6 @@ <# // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #> <#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> @@ -9,7 +9,7 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs index 82a013f70b..48ca391630 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopyTo.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 70a34ddcfa..713f21d2ab 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs index e34af98251..a3e7874707 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs index f106d67ad0..56fb32fb93 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs index 68ab6f9121..007ca5a8f0 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs index 7a92a4ed4e..a36942c529 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs index a646cd6cfe..47a96afd1d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 002f79f84c..c9c740716e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index 8c1b427ee5..663ed44e8a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs index f1d773708c..562fa8f447 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 7ada1b9da4..af7b21fb0a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs index 34fe1aecbd..09adbc44e2 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanBuffer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.IO; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs index fbb2b52727..bc68fb3b00 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index 6025930169..b5f4f1b316 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs index 169b02e9fb..d77b0e8645 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs index 8075fd4bab..7ee8a4b151 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs index 44878bd6c7..8a1389842a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs index db4b6a532b..8bd15ea12a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs index aa33744adf..f7332852db 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegColorSpace.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs index 622c34e9bb..f254f9e86f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index d9fd9ac8b5..aa3ba9c4c5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFileMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFileMarker.cs index d2b0ee26e4..389632caec 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFileMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFileMarker.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs index f426eb1b15..7fc3f0d97a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 5352a0bff7..93de973d55 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs index 325d7780ae..c8ec92f97b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/QualityEvaluator.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/QualityEvaluator.cs index a7d2a0fde9..c304c00b62 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/QualityEvaluator.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/QualityEvaluator.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs index 7a312138d0..714c4f8234 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs index 633d7ea80f..6f5d4700d5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs index a31c4bf2f4..a92e06dac9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs index 2e2ee9575c..acf25a120a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs index d0933af0c4..204652b7e0 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs index cb0810985e..8ae50a167c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs index ba604e8910..38a955f657 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs index dcdc7e9ba7..26c709d5e4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs index 0cc729371f..69c634c359 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // namespace SixLabors.ImageSharp.Formats.Jpeg.Components diff --git a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt index 28bcea791b..4afd1f72d7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.Generated.tt @@ -1,6 +1,6 @@ <# // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #> <#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> @@ -9,7 +9,7 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // namespace SixLabors.ImageSharp.Formats.Jpeg.Components diff --git a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs index 534c66b99d..d72c6f17e2 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs index 8c3daa4d50..971890924f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/RowOctet.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs b/src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs index 94771aa64c..f3e797228f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/SizeExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs b/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs index 669abad28c..801867d561 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs index ef7b377d2b..dc0971e515 100644 --- a/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs +++ b/src/ImageSharp/Formats/Jpeg/IJpegDecoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg { diff --git a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs index 53108de934..5f1a2a99c3 100644 --- a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs +++ b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg { diff --git a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs index 7fec050b4a..36c6d5615b 100644 --- a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs index 9840a2ae88..6719f54988 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg { diff --git a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs index 9f50e2cab1..30a0e4a00e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConstants.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs index e60901d913..97f455c6f9 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 654610659d..a754bfd2e7 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index 1c4035a981..9f3d04a8a2 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index eed95c6b07..21bf538ece 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs index f56072a4b5..4d9899f7a6 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs index 7594f44770..c3b9383482 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs index 9f0deae02c..85506c170b 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg { diff --git a/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs b/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs index 8558157059..71aa0ca229 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Jpeg { diff --git a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs index da4c3f9ee0..2850fd9689 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs index 53a9d2a35d..79383902c2 100644 --- a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/Formats/PixelTypeInfo.cs index 1683519c2b..67d19d7560 100644 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ b/src/ImageSharp/Formats/PixelTypeInfo.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Adam7.cs b/src/ImageSharp/Formats/Png/Adam7.cs index b392332d7a..4290e2ca09 100644 --- a/src/ImageSharp/Formats/Png/Adam7.cs +++ b/src/ImageSharp/Formats/Png/Adam7.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs index 8b3c3e9aad..f26f4262ad 100644 --- a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs +++ b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs index bc5a54e8b9..238e1934ef 100644 --- a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Filters/FilterType.cs b/src/ImageSharp/Formats/Png/Filters/FilterType.cs index 83a005380a..613288c634 100644 --- a/src/ImageSharp/Formats/Png/Filters/FilterType.cs +++ b/src/ImageSharp/Formats/Png/Filters/FilterType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Png.Filters { diff --git a/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs index 97e16ef233..0d1122a3a0 100644 --- a/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index 4cd61e043d..69b9c85afb 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs index e6fc1b6ae6..85bbd90eab 100644 --- a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs index 5d9dc6a890..2f0e0dc198 100644 --- a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs index e3036d4bde..27ef8cc5a6 100644 --- a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Png { diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 0b27539c24..741ec825d4 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Quantization; diff --git a/src/ImageSharp/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs index af56830f42..bdbddd0c6b 100644 --- a/src/ImageSharp/Formats/Png/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/Formats/Png/MetadataExtensions.cs b/src/ImageSharp/Formats/Png/MetadataExtensions.cs index 762a6c40cb..24274531c4 100644 --- a/src/ImageSharp/Formats/Png/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Png/MetadataExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/Formats/Png/PngBitDepth.cs b/src/ImageSharp/Formats/Png/PngBitDepth.cs index 0321b532ab..1af76e746a 100644 --- a/src/ImageSharp/Formats/Png/PngBitDepth.cs +++ b/src/ImageSharp/Formats/Png/PngBitDepth.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // Note the value assignment, This will allow us to add 1, 2, and 4 bit encoding when we support it. namespace SixLabors.ImageSharp.Formats.Png diff --git a/src/ImageSharp/Formats/Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs index 7d8498ab75..1d0337f4f0 100644 --- a/src/ImageSharp/Formats/Png/PngChunk.cs +++ b/src/ImageSharp/Formats/Png/PngChunk.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs index 015f6984d4..2dd9cc8b53 100644 --- a/src/ImageSharp/Formats/Png/PngChunkType.cs +++ b/src/ImageSharp/Formats/Png/PngChunkType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Png { diff --git a/src/ImageSharp/Formats/Png/PngColorType.cs b/src/ImageSharp/Formats/Png/PngColorType.cs index fc376ca161..59a6de335d 100644 --- a/src/ImageSharp/Formats/Png/PngColorType.cs +++ b/src/ImageSharp/Formats/Png/PngColorType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Png { diff --git a/src/ImageSharp/Formats/Png/PngCompressionLevel.cs b/src/ImageSharp/Formats/Png/PngCompressionLevel.cs index 1d93884a33..74c9675448 100644 --- a/src/ImageSharp/Formats/Png/PngCompressionLevel.cs +++ b/src/ImageSharp/Formats/Png/PngCompressionLevel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Png { diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs index 3c9fddbad4..3acbfd87a9 100644 --- a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Png { diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs index 247bb3c756..60f38dda80 100644 --- a/src/ImageSharp/Formats/Png/PngConstants.cs +++ b/src/ImageSharp/Formats/Png/PngConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index eceb4e592f..b2e243997d 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index a5bcff3b2b..d6ba088958 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 95c02b3481..bee0215506 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Advanced; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 34d5ee7739..c150388477 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Png/PngEncoderHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderHelpers.cs index 78cd5d8742..e54d5864a7 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderHelpers.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderHelpers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index a6ac86d547..5545f2c6e9 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Quantization; diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs index 99e64c2fb4..33456eec51 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Advanced; diff --git a/src/ImageSharp/Formats/Png/PngFilterMethod.cs b/src/ImageSharp/Formats/Png/PngFilterMethod.cs index e16c1234f6..aa1899494f 100644 --- a/src/ImageSharp/Formats/Png/PngFilterMethod.cs +++ b/src/ImageSharp/Formats/Png/PngFilterMethod.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Png { diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs index 408e37802f..a0f493b95f 100644 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs index ea43ba96a5..3844a15aa6 100644 --- a/src/ImageSharp/Formats/Png/PngHeader.cs +++ b/src/ImageSharp/Formats/Png/PngHeader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs index 5deed86e30..c294aab3f9 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs index e8c2db1475..6516b84736 100644 --- a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs +++ b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Png { diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 1e4567548b..d3b34fbd7b 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index cf365c8b92..ef3a8034e7 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Png/PngTextData.cs b/src/ImageSharp/Formats/Png/PngTextData.cs index 21171487ea..5b5e4b8ab0 100644 --- a/src/ImageSharp/Formats/Png/PngTextData.cs +++ b/src/ImageSharp/Formats/Png/PngTextData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Png/PngThrowHelper.cs b/src/ImageSharp/Formats/Png/PngThrowHelper.cs index a72a4a0d88..61e986d06d 100644 --- a/src/ImageSharp/Formats/Png/PngThrowHelper.cs +++ b/src/ImageSharp/Formats/Png/PngThrowHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs index c4dc82a4dc..3a5a37ce20 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs index 77355e908c..bc3811b5dc 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflateThrowHelper.cs b/src/ImageSharp/Formats/Png/Zlib/DeflateThrowHelper.cs index 5f62b13c7f..c2296e0136 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflateThrowHelper.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflateThrowHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Zlib/Deflater.cs b/src/ImageSharp/Formats/Png/Zlib/Deflater.cs index 2083edab1c..c99a4c3510 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Deflater.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Deflater.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs index a3a87a32f8..62943a5ae6 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // using System; diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs index c1c86a98be..11b39efb55 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs index 022d3d4d0d..4d1be0fc47 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterOutputStream.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterOutputStream.cs index a777e6f7db..11e566739d 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterOutputStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterOutputStream.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs b/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs index 0414ca2f87..095cb33cc3 100644 --- a/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs +++ b/src/ImageSharp/Formats/Png/Zlib/DeflaterPendingBuffer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs b/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs index da5deb49ef..018508295c 100644 --- a/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs +++ b/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs index 1829330331..4f757e4c92 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index 3eb34b8617..387ff9301f 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs b/src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs index e99e8b0c8d..3d99f136f3 100644 --- a/src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs +++ b/src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Tga { diff --git a/src/ImageSharp/Formats/Tga/ITgaEncoderOptions.cs b/src/ImageSharp/Formats/Tga/ITgaEncoderOptions.cs index 49983d2369..b85431e510 100644 --- a/src/ImageSharp/Formats/Tga/ITgaEncoderOptions.cs +++ b/src/ImageSharp/Formats/Tga/ITgaEncoderOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Tga { diff --git a/src/ImageSharp/Formats/Tga/ImageExtensions.cs b/src/ImageSharp/Formats/Tga/ImageExtensions.cs index 286f04a226..3f9bdacec7 100644 --- a/src/ImageSharp/Formats/Tga/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Tga/ImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/Formats/Tga/MetadataExtensions.cs b/src/ImageSharp/Formats/Tga/MetadataExtensions.cs index 2b0e405e75..e8af82a0ef 100644 --- a/src/ImageSharp/Formats/Tga/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Tga/MetadataExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs b/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs index a0666fa84d..0bba5a4d52 100644 --- a/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Tga { diff --git a/src/ImageSharp/Formats/Tga/TgaCompression.cs b/src/ImageSharp/Formats/Tga/TgaCompression.cs index cc6e005eda..2686afd5b4 100644 --- a/src/ImageSharp/Formats/Tga/TgaCompression.cs +++ b/src/ImageSharp/Formats/Tga/TgaCompression.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Tga { diff --git a/src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs b/src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs index 18fbf4acd0..13bcc54c6b 100644 --- a/src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs +++ b/src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Tga { diff --git a/src/ImageSharp/Formats/Tga/TgaConstants.cs b/src/ImageSharp/Formats/Tga/TgaConstants.cs index 5aabe92a1d..ec84fa4512 100644 --- a/src/ImageSharp/Formats/Tga/TgaConstants.cs +++ b/src/ImageSharp/Formats/Tga/TgaConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Tga/TgaDecoder.cs b/src/ImageSharp/Formats/Tga/TgaDecoder.cs index 64dbdf58a9..abfaba629e 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoder.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 057ec1bfc7..ead0535721 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Formats/Tga/TgaEncoder.cs b/src/ImageSharp/Formats/Tga/TgaEncoder.cs index e938067a1c..6280b2ae63 100644 --- a/src/ImageSharp/Formats/Tga/TgaEncoder.cs +++ b/src/ImageSharp/Formats/Tga/TgaEncoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs index 94bd367aa0..aee3a26ccc 100644 --- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Formats/Tga/TgaFileHeader.cs b/src/ImageSharp/Formats/Tga/TgaFileHeader.cs index e2bbb6fbd2..452c7e4c5b 100644 --- a/src/ImageSharp/Formats/Tga/TgaFileHeader.cs +++ b/src/ImageSharp/Formats/Tga/TgaFileHeader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Formats/Tga/TgaFormat.cs b/src/ImageSharp/Formats/Tga/TgaFormat.cs index badb1d77a4..0afdb30752 100644 --- a/src/ImageSharp/Formats/Tga/TgaFormat.cs +++ b/src/ImageSharp/Formats/Tga/TgaFormat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs index af40c333b6..300172f6c8 100644 --- a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Tga/TgaImageOrigin.cs b/src/ImageSharp/Formats/Tga/TgaImageOrigin.cs index 06d7b59455..6e311a5253 100644 --- a/src/ImageSharp/Formats/Tga/TgaImageOrigin.cs +++ b/src/ImageSharp/Formats/Tga/TgaImageOrigin.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Tga { diff --git a/src/ImageSharp/Formats/Tga/TgaImageType.cs b/src/ImageSharp/Formats/Tga/TgaImageType.cs index 491fd3ea77..4ee95ccb51 100644 --- a/src/ImageSharp/Formats/Tga/TgaImageType.cs +++ b/src/ImageSharp/Formats/Tga/TgaImageType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors. ImageSharp.Formats.Tga diff --git a/src/ImageSharp/Formats/Tga/TgaImageTypeExtensions.cs b/src/ImageSharp/Formats/Tga/TgaImageTypeExtensions.cs index 6a30cdddd7..b8b8b75c49 100644 --- a/src/ImageSharp/Formats/Tga/TgaImageTypeExtensions.cs +++ b/src/ImageSharp/Formats/Tga/TgaImageTypeExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Tga { diff --git a/src/ImageSharp/Formats/Tga/TgaMetadata.cs b/src/ImageSharp/Formats/Tga/TgaMetadata.cs index 69dee768a9..17225ea0cf 100644 --- a/src/ImageSharp/Formats/Tga/TgaMetadata.cs +++ b/src/ImageSharp/Formats/Tga/TgaMetadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Formats.Tga { diff --git a/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs b/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs index fc158e781e..c6df287d8e 100644 --- a/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs +++ b/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/GeometryUtilities.cs b/src/ImageSharp/GeometryUtilities.cs index 00fa5b97f1..4e82442f6c 100644 --- a/src/ImageSharp/GeometryUtilities.cs +++ b/src/ImageSharp/GeometryUtilities.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs index c8beea8e85..4912f55c84 100644 --- a/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs +++ b/src/ImageSharp/GraphicOptionsDefaultsExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Processing; diff --git a/src/ImageSharp/GraphicsOptions.cs b/src/ImageSharp/GraphicsOptions.cs index 47b930e654..8c30605475 100644 --- a/src/ImageSharp/GraphicsOptions.cs +++ b/src/ImageSharp/GraphicsOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/IConfigurationModule.cs b/src/ImageSharp/IConfigurationModule.cs index 3ca8ed9182..a47bb89bb1 100644 --- a/src/ImageSharp/IConfigurationModule.cs +++ b/src/ImageSharp/IConfigurationModule.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp { diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs index f80247a5d0..caf837b662 100644 --- a/src/ImageSharp/IDeepCloneable.cs +++ b/src/ImageSharp/IDeepCloneable.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp { diff --git a/src/ImageSharp/IImage.cs b/src/ImageSharp/IImage.cs index 0d4dc3c9d9..8e9df0108f 100644 --- a/src/ImageSharp/IImage.cs +++ b/src/ImageSharp/IImage.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/IImageInfo.cs b/src/ImageSharp/IImageInfo.cs index b270c2c4de..92ff5c5c3e 100644 --- a/src/ImageSharp/IImageInfo.cs +++ b/src/ImageSharp/IImageInfo.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/IO/DoubleBufferedStreamReader.cs b/src/ImageSharp/IO/DoubleBufferedStreamReader.cs index 0345717d21..f0d9620eba 100644 --- a/src/ImageSharp/IO/DoubleBufferedStreamReader.cs +++ b/src/ImageSharp/IO/DoubleBufferedStreamReader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/IO/IFileSystem.cs b/src/ImageSharp/IO/IFileSystem.cs index 9dc97afb60..75d844daba 100644 --- a/src/ImageSharp/IO/IFileSystem.cs +++ b/src/ImageSharp/IO/IFileSystem.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/IO/LocalFileSystem.cs b/src/ImageSharp/IO/LocalFileSystem.cs index 11f3d79723..4a3b68ea9d 100644 --- a/src/ImageSharp/IO/LocalFileSystem.cs +++ b/src/ImageSharp/IO/LocalFileSystem.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index c28a214525..cb6f01ce49 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index a0e8097d8e..3cd6228a18 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index 8546dd2700..91b6ca3a72 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 332ca471e9..bcd11845bb 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Image.LoadPixelData.cs b/src/ImageSharp/Image.LoadPixelData.cs index f36243cc3e..8b827f170d 100644 --- a/src/ImageSharp/Image.LoadPixelData.cs +++ b/src/ImageSharp/Image.LoadPixelData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index 0dd8c814d0..03b5cb9a02 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index b1cefdf1d9..c43a208425 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/ImageExtensions.Internal.cs b/src/ImageSharp/ImageExtensions.Internal.cs index a1fc51043e..65e2701a2e 100644 --- a/src/ImageSharp/ImageExtensions.Internal.cs +++ b/src/ImageSharp/ImageExtensions.Internal.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index e5b2a32a99..aa9030c6ef 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/ImageFrame.LoadPixelData.cs b/src/ImageSharp/ImageFrame.LoadPixelData.cs index e6035a177f..a5a7924722 100644 --- a/src/ImageSharp/ImageFrame.LoadPixelData.cs +++ b/src/ImageSharp/ImageFrame.LoadPixelData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/ImageFrame.cs b/src/ImageSharp/ImageFrame.cs index 93fa205876..38c853fd75 100644 --- a/src/ImageSharp/ImageFrame.cs +++ b/src/ImageSharp/ImageFrame.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Advanced; diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index c584d2d193..75b7fe84c6 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections; diff --git a/src/ImageSharp/ImageFrameCollection{TPixel}.cs b/src/ImageSharp/ImageFrameCollection{TPixel}.cs index 89a1dfcc16..1e674198b0 100644 --- a/src/ImageSharp/ImageFrameCollection{TPixel}.cs +++ b/src/ImageSharp/ImageFrameCollection{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections; diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 0171f3d07f..be4e988c68 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/ImageInfo.cs b/src/ImageSharp/ImageInfo.cs index 12dcf1ed74..baff7fd08a 100644 --- a/src/ImageSharp/ImageInfo.cs +++ b/src/ImageSharp/ImageInfo.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Metadata; diff --git a/src/ImageSharp/ImageInfoExtensions.cs b/src/ImageSharp/ImageInfoExtensions.cs index abaa7c4bc4..f87b19b1a0 100644 --- a/src/ImageSharp/ImageInfoExtensions.cs +++ b/src/ImageSharp/ImageInfoExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp { diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 2ab4728532..7eda2050ae 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/IndexedImageFrame{TPixel}.cs b/src/ImageSharp/IndexedImageFrame{TPixel}.cs index 07451029e6..410cd76553 100644 --- a/src/ImageSharp/IndexedImageFrame{TPixel}.cs +++ b/src/ImageSharp/IndexedImageFrame{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Memory/Allocators/AllocationOptions.cs b/src/ImageSharp/Memory/Allocators/AllocationOptions.cs index 4edb702ed9..7c97f08b3d 100644 --- a/src/ImageSharp/Memory/Allocators/AllocationOptions.cs +++ b/src/ImageSharp/Memory/Allocators/AllocationOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Memory { diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs index f943598301..a468feceea 100644 --- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs index 5ef60c9ed6..b0ea00f5b6 100644 --- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs +++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Memory { diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs index 4a04cb5d6e..57d8c0e452 100644 --- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs b/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs index cb1f58ddba..ef17e69536 100644 --- a/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs +++ b/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers; diff --git a/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs b/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs index 56057f3726..d88e0bd5de 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs b/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs index 571ad70c5d..b3ece76eb5 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Memory.Internals { diff --git a/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs b/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs index 8909638600..ca4483e3b6 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/ManagedBufferBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs index a4e1de1977..71564836b0 100644 --- a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs index 4c62e4ded5..5996d0c49a 100644 --- a/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers; using SixLabors.ImageSharp.Memory.Internals; diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index 11c61f56cc..56de1fd078 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/src/ImageSharp/Memory/Buffer2DRegion{T}.cs b/src/ImageSharp/Memory/Buffer2DRegion{T}.cs index b22307a1d5..2a44a4b721 100644 --- a/src/ImageSharp/Memory/Buffer2DRegion{T}.cs +++ b/src/ImageSharp/Memory/Buffer2DRegion{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index ada1d29b6d..6c8741c5db 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs index 3bb6b8d336..8f46ae3b84 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs index 1bc44e33e1..64f7e368c6 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupEnumerator{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.ComponentModel; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs index 295f9190a9..ca8123f6ae 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs index 1698f08d17..d301b528d8 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs index 1dfbaea932..3f21d768c8 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs index 5a86ac4268..041e5838a0 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 6fd93f12ea..f010855bc9 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Memory/InvalidMemoryOperationException.cs b/src/ImageSharp/Memory/InvalidMemoryOperationException.cs index c1d5c5d416..88df49bd33 100644 --- a/src/ImageSharp/Memory/InvalidMemoryOperationException.cs +++ b/src/ImageSharp/Memory/InvalidMemoryOperationException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs index 22d1bddd2f..1595b0f48f 100644 --- a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs +++ b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers; diff --git a/src/ImageSharp/Memory/MemoryOwnerExtensions.cs b/src/ImageSharp/Memory/MemoryOwnerExtensions.cs index 6d4468f788..d86b1e7846 100644 --- a/src/ImageSharp/Memory/MemoryOwnerExtensions.cs +++ b/src/ImageSharp/Memory/MemoryOwnerExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Memory/RowInterval.cs b/src/ImageSharp/Memory/RowInterval.cs index c2962cfe97..4f3df7df57 100644 --- a/src/ImageSharp/Memory/RowInterval.cs +++ b/src/ImageSharp/Memory/RowInterval.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Memory/TransformItemsDelegate{T}.cs b/src/ImageSharp/Memory/TransformItemsDelegate{T}.cs index 31825b7b41..5e14e90f28 100644 --- a/src/ImageSharp/Memory/TransformItemsDelegate{T}.cs +++ b/src/ImageSharp/Memory/TransformItemsDelegate{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Memory/TransformItemsInplaceDelegate.cs b/src/ImageSharp/Memory/TransformItemsInplaceDelegate.cs index 023606f521..e6981548b9 100644 --- a/src/ImageSharp/Memory/TransformItemsInplaceDelegate.cs +++ b/src/ImageSharp/Memory/TransformItemsInplaceDelegate.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/FrameDecodingMode.cs b/src/ImageSharp/Metadata/FrameDecodingMode.cs index 835e43354a..55cfdc6ab4 100644 --- a/src/ImageSharp/Metadata/FrameDecodingMode.cs +++ b/src/ImageSharp/Metadata/FrameDecodingMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata { diff --git a/src/ImageSharp/Metadata/ImageFrameMetadata.cs b/src/ImageSharp/Metadata/ImageFrameMetadata.cs index 3858a7d0a3..19b4d8aa63 100644 --- a/src/ImageSharp/Metadata/ImageFrameMetadata.cs +++ b/src/ImageSharp/Metadata/ImageFrameMetadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.Formats; diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs index 716e89e68d..a9b2e9658f 100644 --- a/src/ImageSharp/Metadata/ImageMetadata.cs +++ b/src/ImageSharp/Metadata/ImageMetadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.Formats; diff --git a/src/ImageSharp/Metadata/PixelResolutionUnit.cs b/src/ImageSharp/Metadata/PixelResolutionUnit.cs index 661e7a308e..d894ce8777 100644 --- a/src/ImageSharp/Metadata/PixelResolutionUnit.cs +++ b/src/ImageSharp/Metadata/PixelResolutionUnit.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs index c58b224e49..f2c2370945 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs index 74c86f7214..d6273f0dcb 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs index d94dc56401..870a7714ab 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs index 6405a7ff2b..189edf8ca5 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs index 29c21d6113..2c26cfd574 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 6ad8d24fa4..1e944b9998 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs index b9bb2ee056..c1f3aaf9a6 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Reflection; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs index a4123d02fe..38ef491975 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs index b00813730d..70d2664ff7 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs index dc33fd8b0a..0f22d358a6 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs index 2bfa8ff213..ef59c9d909 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs index 6cbae4c558..76482fb75f 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs index 571b50efb6..8f2fd3e627 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs index 120f2dab0f..e164f3c628 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs index 6cea52b1a5..9c3e30d502 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs index b515ab36a5..ddc0d3b0f9 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs index 2281dee49c..a53f815791 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs index cf43a8a8a4..741e40c7d5 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs index 7fe9a58bcd..6bca94afd6 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs index 90485f75ab..f5a386cb87 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs index 29d61db88c..00d29ad4a8 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs index 9a6e3063b0..954b544a67 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs index 506f874548..24a4789c1c 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs index 5f48412263..4a2af0bff3 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs index 65e0314626..35a6fbab9a 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs index f70bcea37a..a35b3301c2 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs index 5a674277a2..6b727e8dbf 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs index 8f0b36638c..51cab264ad 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs index 263bf09348..3d1282ca45 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs index 184f4a07c4..d55447ed7b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs index 854eafc767..83819844d0 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs index 0af5f47ce2..2d0ac3a0f2 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDoubleArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDoubleArray.cs index 259d5c98a2..6157cffc98 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDoubleArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDoubleArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs index 8d6c41f58e..4c53b36cfd 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloatArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloatArray.cs index 7789bc3b5d..3dfd2989db 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloatArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloatArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs index 7f2f631a97..98d016af0c 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs index e05f50beee..944cd6ceb9 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs index ef7d20c855..a36eae16ff 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs index 521cfc0857..414996ed17 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs index 3ab77ab321..2afca7dbab 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs index f78e363da4..866e8d22b2 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs index b11f3fc9f9..c8837b82e6 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs index 379338c10f..39d0bac4dc 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs index a9cb013ca5..8d18f8eb7b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs index b0d35cc8a8..6da81f77b3 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong.cs index c1e6808bf4..be5aef3d06 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs index 36d4c00077..e94f66b597 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRational.cs index 61fba979b3..90c30501c9 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRational.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRational.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRationalArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRationalArray.cs index 2545bd9b27..88927c548b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRationalArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRationalArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs index e00f5c085b..a460f1407f 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs index 403a501863..14bb590719 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifString.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifString.cs index 0678bc3e41..a4429de7dd 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifString.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifString.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs index 547e099c92..0c6f61d188 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs index 62d3f40ac2..f5caf1583a 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue{TValueType}.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue{TValueType}.cs index 601630af6b..25b8d1dbb1 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue{TValueType}.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue{TValueType}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs index 50c4218320..ca780448c1 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue{TValueType}.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue{TValueType}.cs index 72b93ddf9e..9631d780a3 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue{TValueType}.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue{TValueType}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccCurveSegment.cs b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccCurveSegment.cs index 7bf1f84211..6880385d10 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccCurveSegment.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccCurveSegment.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs index d013f6ef13..ec2f9bd015 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccFormulaCurveElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccOneDimensionalCurve.cs b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccOneDimensionalCurve.cs index cbb433012d..36877916a5 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccOneDimensionalCurve.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccOneDimensionalCurve.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccParametricCurve.cs b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccParametricCurve.cs index 04a9faf7da..a6cedd5307 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccParametricCurve.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccParametricCurve.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccResponseCurve.cs b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccResponseCurve.cs index b9a50acd47..c55c145fdf 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccResponseCurve.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccResponseCurve.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccSampledCurveElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccSampledCurveElement.cs index 4872bd2b08..30e9bf4b49 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccSampledCurveElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Curves/IccSampledCurveElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Curves.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Curves.cs index 58ca46d816..4f9cebce4b 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Curves.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Curves.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs index 0aa3c31e08..dd3c5020be 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Matrix.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Matrix.cs index ecc33dd776..7541fe1e37 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Matrix.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Matrix.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.MultiProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.MultiProcessElement.cs index b854247da3..7cbb146ec2 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.MultiProcessElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.MultiProcessElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs index b5326225cf..bbeb2f2110 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.NonPrimitives.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Primitives.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Primitives.cs index 3f016444bd..00c902339c 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Primitives.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Primitives.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs index a30e45ddeb..91dd8bbc1b 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.cs index 79542b85fd..14ad06bb87 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Curves.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Curves.cs index 4f03ed6101..6a7564ec4c 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Curves.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Curves.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Lut.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Lut.cs index 016bd8009a..fd9310e74c 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Lut.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Lut.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs index 585892e96a..d03d173308 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.MultiProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.MultiProcessElement.cs index 65490f1807..2854fb3e89 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.MultiProcessElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.MultiProcessElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs index ce80574ad3..4af49e5db3 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.NonPrimitives.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs index 6c49eb0c43..2053fed410 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Text; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs index b761f48ba0..5577d7c24a 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.cs index 17f15df714..9c72fa3e53 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/DataWriter/IccDataWriter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccClutDataType.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccClutDataType.cs index 71e68f6af1..e1306e689a 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccClutDataType.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccClutDataType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccColorSpaceType.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccColorSpaceType.cs index 721545df36..649e2700c9 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccColorSpaceType.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccColorSpaceType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccColorantEncoding.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccColorantEncoding.cs index 14b2dd960f..d42195cd10 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccColorantEncoding.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccColorantEncoding.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccCurveMeasurementEncodings.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccCurveMeasurementEncodings.cs index a620632da6..5b58b74c20 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccCurveMeasurementEncodings.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccCurveMeasurementEncodings.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccCurveSegmentSignature.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccCurveSegmentSignature.cs index 9a5ae18052..a66556cbee 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccCurveSegmentSignature.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccCurveSegmentSignature.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs index de1f116366..57a25e2542 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDataType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDeviceAttribute.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDeviceAttribute.cs index c8598b0e03..0428789e2e 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDeviceAttribute.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccDeviceAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccFormulaCurveType.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccFormulaCurveType.cs index 11e5985af3..be43bc3fff 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccFormulaCurveType.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccFormulaCurveType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccMeasurementGeometry.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccMeasurementGeometry.cs index 9373241949..4849fa3af5 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccMeasurementGeometry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccMeasurementGeometry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccMultiProcessElementSignature.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccMultiProcessElementSignature.cs index d7f78889dc..2f216ff374 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccMultiProcessElementSignature.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccMultiProcessElementSignature.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccParametricCurveType.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccParametricCurveType.cs index fce08a3afe..9d87d95487 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccParametricCurveType.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccParametricCurveType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccPrimaryPlatformType.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccPrimaryPlatformType.cs index 035fd3d4d2..07abc024f6 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccPrimaryPlatformType.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccPrimaryPlatformType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileClass.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileClass.cs index 3d59192a7b..db49aa4ce4 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileClass.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileClass.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileFlag.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileFlag.cs index 9fbe5b5b5a..fc1f3237cc 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileFlag.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileFlag.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileTag.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileTag.cs index b19641e0fb..cb901028b7 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileTag.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccProfileTag.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Metadata.Profiles.Icc diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccRenderingIntent.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccRenderingIntent.cs index 8ae241b448..301b7448f8 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccRenderingIntent.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccRenderingIntent.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccScreeningFlag.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccScreeningFlag.cs index b43ad52c48..ead39c3c57 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccScreeningFlag.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccScreeningFlag.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccScreeningSpotType.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccScreeningSpotType.cs index 0631892b62..414db39bfb 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccScreeningSpotType.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccScreeningSpotType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccSignatureName.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccSignatureName.cs index f93d22f3e4..af3c7a3f05 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccSignatureName.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccSignatureName.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccStandardIlluminant.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccStandardIlluminant.cs index fc8ebae5cd..961a7f2cd4 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccStandardIlluminant.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccStandardIlluminant.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccStandardObserver.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccStandardObserver.cs index 14c0a04678..fb5e8cac49 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccStandardObserver.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccStandardObserver.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccTypeSignature.cs b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccTypeSignature.cs index d7a18579e5..751020c3c5 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccTypeSignature.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Enums/IccTypeSignature.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Icc { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Exceptions/InvalidIccProfileException.cs b/src/ImageSharp/Metadata/Profiles/ICC/Exceptions/InvalidIccProfileException.cs index 019bf9202c..3d031e25bc 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Exceptions/InvalidIccProfileException.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Exceptions/InvalidIccProfileException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs index 7c5139475b..53157b95ef 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Security.Cryptography; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccProfileHeader.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccProfileHeader.cs index 326dd351e7..d5962318b6 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccProfileHeader.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccProfileHeader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs index 30a6de40d0..9c02f3a8cd 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccReader.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs index 658d4c2f1b..6bdd6b9938 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs index 186f06df05..e1e181dc6e 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccWriter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccBAcsProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccBAcsProcessElement.cs index c825a35352..f95236f29a 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccBAcsProcessElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccBAcsProcessElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccClutProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccClutProcessElement.cs index 7ee7f821d7..4e68c411be 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccClutProcessElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccClutProcessElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs index c6409e3c1d..397a9c2927 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccEAcsProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccEAcsProcessElement.cs index d6f42aea76..1ad702da07 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccEAcsProcessElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccEAcsProcessElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs index 668883e1ae..0208220d90 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccMatrixProcessElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccMultiProcessElement.cs b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccMultiProcessElement.cs index 24649d8b50..6bbee5b8df 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccMultiProcessElement.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/MultiProcessElements/IccMultiProcessElement.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs index 813271d48b..072644827f 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs index 4136b9a389..bed0446b13 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs index aff33ff828..881b144277 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs index bcf9d5c9e1..998e8d920d 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs index f2205cbad5..43592cc9d6 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs index 6a0b6c05e8..118f0d0bd1 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Text; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs index 371397a6f8..56c25a7c73 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs index 50bfca1756..46e3038969 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs index 8f7db49ad0..d8d13a15ed 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs index 3a1859a1c3..190265fe9c 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs index 0dfaef7d40..223165acdf 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs index 929a70ed86..b0f20a08b6 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs index ad3a9f2c36..68440870dc 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs index 34a027126f..8c61f77442 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs index f2713e8cee..966b1cb6d4 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccNamedColor2TagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccNamedColor2TagDataEntry.cs index 4fd0cfcfb6..457ee49b47 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccNamedColor2TagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccNamedColor2TagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccParametricCurveTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccParametricCurveTagDataEntry.cs index 752d05aae2..b384d10fec 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccParametricCurveTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccParametricCurveTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs index 7897c394f1..9a5c108e91 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccProfileSequenceIdentifierTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccProfileSequenceIdentifierTagDataEntry.cs index 06e52cb637..26dea9d1bf 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccProfileSequenceIdentifierTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccProfileSequenceIdentifierTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs index e9c8af9be2..3db6afccb5 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccResponseCurveSet16TagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs index bf64e4fed0..a9761a2704 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs index 87d369f85b..70d982f0bc 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs index 23e81fe993..0791cd77d3 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs index 6cf9e91543..0e6e82679b 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs index 3e4a5ff3a9..49cd4518e4 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs index 46799b16a9..0c41770d73 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs index 9fbbf8bf57..7f5de5b880 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs index 09bec9b7a5..7e18675d60 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs index 099916d894..94740250c4 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs index d28b6edc96..b0f2325a8c 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs index 0227983fa1..feea432934 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccViewingConditionsTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccViewingConditionsTagDataEntry.cs index 2b2893c388..fe60ca6dab 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccViewingConditionsTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccViewingConditionsTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs index 1e7d532310..67f25934c3 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs index bd8f784ae7..14c11cfa5f 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccClut.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccColorantTableEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccColorantTableEntry.cs index db1feea9ab..60fc7e54f5 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccColorantTableEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccColorantTableEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccLocalizedString.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccLocalizedString.cs index b2852c8a33..c8d097d382 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccLocalizedString.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccLocalizedString.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccLut.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccLut.cs index 9e0c6c40dd..bacf3f22a8 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccLut.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccLut.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccNamedColor.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccNamedColor.cs index 3c640ab036..c55a1849a6 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccNamedColor.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccNamedColor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccPositionNumber.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccPositionNumber.cs index c9b75903d9..959269b4e1 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccPositionNumber.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccPositionNumber.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileDescription.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileDescription.cs index d630f015e9..476f43c263 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileDescription.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileDescription.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs index 4a73f7e079..c113e8ddf5 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileId.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileSequenceIdentifier.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileSequenceIdentifier.cs index 6bf420b49e..7818229e15 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileSequenceIdentifier.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccProfileSequenceIdentifier.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccResponseNumber.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccResponseNumber.cs index 8590802638..ea9f3286c4 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccResponseNumber.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccResponseNumber.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccScreeningChannel.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccScreeningChannel.cs index 354442b476..7736255c3a 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccScreeningChannel.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccScreeningChannel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccTagTableEntry.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccTagTableEntry.cs index 889dec41eb..1ce66146eb 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccTagTableEntry.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccTagTableEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccVersion.cs b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccVersion.cs index b388fa5a48..d8f5b13fe7 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/Various/IccVersion.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/Various/IccVersion.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs index f138cc650f..6e864db147 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcProfile.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs index 7258a02917..68807918c9 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTag.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs index 6b39769a7f..525d90c892 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcTagExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Metadata.Profiles.Iptc { diff --git a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs index e63781012a..a09239b8df 100644 --- a/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs +++ b/src/ImageSharp/Metadata/Profiles/IPTC/IptcValue.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Text; diff --git a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs index e8cfaa462e..3110e45992 100644 --- a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs +++ b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs b/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs index 6775cbc589..47962ef202 100644 --- a/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs +++ b/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 6d1c03e4bb..5d4d3ff94b 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs b/src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs index b2f6261ef5..46f13f0084 100644 --- a/src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs +++ b/src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.PixelFormats { diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index f966de63cd..6ad5af8e56 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // using System; diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index a882de066e..d2633ae3fd 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -1,6 +1,6 @@ <# // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #> <#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> @@ -9,7 +9,7 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // using System; diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index 8184f1577b..9a385937e0 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index be2beb2f8e..1869eb3c90 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -1,6 +1,6 @@ <# // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #> <#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> @@ -9,7 +9,7 @@ <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs index 97b4458aff..54cf72ae80 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 244aba7de6..17cd33d555 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/PixelFormats/PixelColorBlendingMode.cs b/src/ImageSharp/PixelFormats/PixelColorBlendingMode.cs index a68f7d9492..d3c0dc13d3 100644 --- a/src/ImageSharp/PixelFormats/PixelColorBlendingMode.cs +++ b/src/ImageSharp/PixelFormats/PixelColorBlendingMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.PixelFormats { diff --git a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs index eb64e532ea..c5124ebe6b 100644 --- a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs +++ b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/PixelFormats/PixelConversionModifiersExtensions.cs b/src/ImageSharp/PixelFormats/PixelConversionModifiersExtensions.cs index 529041481f..5d08ee69c7 100644 --- a/src/ImageSharp/PixelFormats/PixelConversionModifiersExtensions.cs +++ b/src/ImageSharp/PixelFormats/PixelConversionModifiersExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 444221d88a..114ed46b47 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 52f6bcaa19..925f0c301e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 0a2f58409f..13a38e8112 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 2659689bda..e2c24efdf5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 40c187eb27..0faaca257c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index bbbf9145c7..e1246f2768 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index d10d10b477..06f5532efb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index 49b4f4138e..296bb3df14 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs index 83bc46d8ec..8d0a86a129 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs index 8f21ef2d4e..23b91c5f82 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs index 58a68bd031..7892a2de00 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra5551.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra5551.PixelOperations.Generated.cs index 4def59ea11..2512518420 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra5551.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra5551.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/L16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/L16.PixelOperations.Generated.cs index dd9a3ac10f..e7bdb1ebe4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/L16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/L16.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/L8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/L8.PixelOperations.Generated.cs index 6a5ec6971f..95612035a6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/L8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/L8.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/La16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/La16.PixelOperations.Generated.cs index 66e8d7dc07..3c4624c093 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/La16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/La16.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/La32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/La32.PixelOperations.Generated.cs index e3f0330083..0b01a215b7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/La32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/La32.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs index face124a6e..081f33573f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs index 6828079c23..cd69247331 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs index 6437b04091..0a621748e7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs index c48493faf0..ac04da77b6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude index 076db616b2..f8427ed534 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -4,7 +4,7 @@ <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index 977df78b8f..788cb4b598 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 1ecaa05da1..dfd4aa838a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 35822779fe..1575c8e5e4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 815ae6a4e3..78bd8e4b88 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 37a028db25..5fb2834f68 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 104c2be45a..410cd853eb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index 98a6cdae49..3c5b600349 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index 54effcb227..930d8d2960 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index a7b350d557..28d81a8b6a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 6be347bccc..672a86defc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 59433f17e2..653aaafd58 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 60c4010039..436711e912 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 6e4839fed7..099ea2105f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index dff8fe83fe..ffc42ad1fa 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 7ca47f8387..de69ad172d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs index 0b0e9b1c18..aa66bbf663 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 43ec095a12..2a3cbf3aa1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 8e5f8f0938..b9539bac31 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs index 0f98712443..fd59222fd1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 8a6f882c35..688e488248 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 526e831f85..16c7da0d30 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 135aa8d582..43b4649d46 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index d1f4a11c72..2c620eeaa4 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // using System; diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index d242739645..286745a92b 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -1,6 +1,6 @@ <# // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #> <#@ template debug="false" hostspecific="false" language="C#" #> <#@ assembly name="System.Core" #> @@ -97,7 +97,7 @@ #> // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // using System; diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs index 17af972a80..11a85cf885 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats.PixelBlenders; diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 1e1047e2b1..42d7992cf6 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/PixelFormats/RgbaComponent.cs b/src/ImageSharp/PixelFormats/RgbaComponent.cs index 76df62c437..29f3ef4f1b 100644 --- a/src/ImageSharp/PixelFormats/RgbaComponent.cs +++ b/src/ImageSharp/PixelFormats/RgbaComponent.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp { diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs index 12ec389b06..1671034777 100644 --- a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers.Binary; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs index ac50dd8c44..614925f199 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index 4ee645c207..e49efd5c3e 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs index ba676b3b88..83edef0640 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Primitives/ColorMatrix.cs b/src/ImageSharp/Primitives/ColorMatrix.cs index 09a2d17ae1..24be37fadc 100644 --- a/src/ImageSharp/Primitives/ColorMatrix.cs +++ b/src/ImageSharp/Primitives/ColorMatrix.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #pragma warning disable SA1117 // Parameters should be on same line or separate lines using System; diff --git a/src/ImageSharp/Primitives/Complex64.cs b/src/ImageSharp/Primitives/Complex64.cs index a5af3f2f71..4a3c564b8e 100644 --- a/src/ImageSharp/Primitives/Complex64.cs +++ b/src/ImageSharp/Primitives/Complex64.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Primitives/ComplexVector4.cs b/src/ImageSharp/Primitives/ComplexVector4.cs index 5287ab23ff..1cc1e8e68f 100644 --- a/src/ImageSharp/Primitives/ComplexVector4.cs +++ b/src/ImageSharp/Primitives/ComplexVector4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 3fda03b77d..4393e4e66b 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/src/ImageSharp/Primitives/LongRational.cs b/src/ImageSharp/Primitives/LongRational.cs index d0f56917e1..248cb2e271 100644 --- a/src/ImageSharp/Primitives/LongRational.cs +++ b/src/ImageSharp/Primitives/LongRational.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/src/ImageSharp/Primitives/Matrix3x2Extensions.cs b/src/ImageSharp/Primitives/Matrix3x2Extensions.cs index 4ddbcc0173..0675ff4641 100644 --- a/src/ImageSharp/Primitives/Matrix3x2Extensions.cs +++ b/src/ImageSharp/Primitives/Matrix3x2Extensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Primitives/Number.cs b/src/ImageSharp/Primitives/Number.cs index 3d575e866b..81adf10130 100644 --- a/src/ImageSharp/Primitives/Number.cs +++ b/src/ImageSharp/Primitives/Number.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/src/ImageSharp/Primitives/Point.cs b/src/ImageSharp/Primitives/Point.cs index 96e73766b9..6776e584d4 100644 --- a/src/ImageSharp/Primitives/Point.cs +++ b/src/ImageSharp/Primitives/Point.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.ComponentModel; diff --git a/src/ImageSharp/Primitives/PointF.cs b/src/ImageSharp/Primitives/PointF.cs index e43ad4daf1..d8918a52c9 100644 --- a/src/ImageSharp/Primitives/PointF.cs +++ b/src/ImageSharp/Primitives/PointF.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.ComponentModel; diff --git a/src/ImageSharp/Primitives/Rational.cs b/src/ImageSharp/Primitives/Rational.cs index 212178a246..7c55d8f17b 100644 --- a/src/ImageSharp/Primitives/Rational.cs +++ b/src/ImageSharp/Primitives/Rational.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/src/ImageSharp/Primitives/Rectangle.cs b/src/ImageSharp/Primitives/Rectangle.cs index d391057a9b..eac5cf04cc 100644 --- a/src/ImageSharp/Primitives/Rectangle.cs +++ b/src/ImageSharp/Primitives/Rectangle.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.ComponentModel; diff --git a/src/ImageSharp/Primitives/RectangleF.cs b/src/ImageSharp/Primitives/RectangleF.cs index 354daa4463..05af7b430a 100644 --- a/src/ImageSharp/Primitives/RectangleF.cs +++ b/src/ImageSharp/Primitives/RectangleF.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.ComponentModel; diff --git a/src/ImageSharp/Primitives/SignedRational.cs b/src/ImageSharp/Primitives/SignedRational.cs index 93a0ffe39f..440fbd71eb 100644 --- a/src/ImageSharp/Primitives/SignedRational.cs +++ b/src/ImageSharp/Primitives/SignedRational.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/src/ImageSharp/Primitives/Size.cs b/src/ImageSharp/Primitives/Size.cs index effd657a6c..099a56c43a 100644 --- a/src/ImageSharp/Primitives/Size.cs +++ b/src/ImageSharp/Primitives/Size.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.ComponentModel; diff --git a/src/ImageSharp/Primitives/SizeF.cs b/src/ImageSharp/Primitives/SizeF.cs index 7d9bc58146..ff8ea1950b 100644 --- a/src/ImageSharp/Primitives/SizeF.cs +++ b/src/ImageSharp/Primitives/SizeF.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.ComponentModel; diff --git a/src/ImageSharp/Primitives/ValueSize.cs b/src/ImageSharp/Primitives/ValueSize.cs index be2ccb7251..996f0979da 100644 --- a/src/ImageSharp/Primitives/ValueSize.cs +++ b/src/ImageSharp/Primitives/ValueSize.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs index 3279d96e3a..d4f376a31a 100644 --- a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs +++ b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Binarization; diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs index 1478d2951b..66e46f683e 100644 --- a/src/ImageSharp/Processing/AffineTransformBuilder.cs +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Processing/AnchorPositionMode.cs b/src/ImageSharp/Processing/AnchorPositionMode.cs index ef9c0fdaf2..d492ed5e81 100644 --- a/src/ImageSharp/Processing/AnchorPositionMode.cs +++ b/src/ImageSharp/Processing/AnchorPositionMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/ColorBlindnessMode.cs b/src/ImageSharp/Processing/ColorBlindnessMode.cs index 2ff19e77e4..78b54744f1 100644 --- a/src/ImageSharp/Processing/ColorBlindnessMode.cs +++ b/src/ImageSharp/Processing/ColorBlindnessMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs b/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs index 714a45f5f0..e65e440723 100644 --- a/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs +++ b/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/EdgeDetectionOperators.cs b/src/ImageSharp/Processing/EdgeDetectionOperators.cs index 1f3526760e..e36df76bc1 100644 --- a/src/ImageSharp/Processing/EdgeDetectionOperators.cs +++ b/src/ImageSharp/Processing/EdgeDetectionOperators.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/Extensions/Binarization/BinaryDitherExtensions.cs b/src/ImageSharp/Processing/Extensions/Binarization/BinaryDitherExtensions.cs index 659b538fcc..f52aab0153 100644 --- a/src/ImageSharp/Processing/Extensions/Binarization/BinaryDitherExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Binarization/BinaryDitherExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Dithering; diff --git a/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs b/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs index d4fe9b562e..55fe2501b7 100644 --- a/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Binarization; diff --git a/src/ImageSharp/Processing/Extensions/Convolution/BokehBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/BokehBlurExtensions.cs index 7e0b3df390..08ae60623c 100644 --- a/src/ImageSharp/Processing/Extensions/Convolution/BokehBlurExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Convolution/BokehBlurExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs index 4534e474a9..ba9b84f19d 100644 --- a/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs index 53b2d40b0d..d1ce9cdf71 100644 --- a/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs index 9c40d94ed7..a8b7bf1904 100644 --- a/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs index 007fffb1a2..7dd6823b8c 100644 --- a/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/src/ImageSharp/Processing/Extensions/Dithering/DitherExtensions.cs b/src/ImageSharp/Processing/Extensions/Dithering/DitherExtensions.cs index a04aa0df82..c595cc83bf 100644 --- a/src/ImageSharp/Processing/Extensions/Dithering/DitherExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Dithering/DitherExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Processing.Processors.Dithering; diff --git a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs index 3c25bb7c40..048ccf1be1 100644 --- a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Drawing; diff --git a/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs b/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs index 5216172819..aafab4b997 100644 --- a/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Effects; diff --git a/src/ImageSharp/Processing/Extensions/Effects/PixelRowDelegateExtensions.cs b/src/ImageSharp/Processing/Extensions/Effects/PixelRowDelegateExtensions.cs index b622141b73..84c5cb4229 100644 --- a/src/ImageSharp/Processing/Extensions/Effects/PixelRowDelegateExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Effects/PixelRowDelegateExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Effects; diff --git a/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs b/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs index f2a10532d0..0639c5a167 100644 --- a/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Effects; diff --git a/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs index 788677fc80..92abd0ff08 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/BrightnessExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/BrightnessExtensions.cs index 7bc441297e..02d73d42ab 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/BrightnessExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/BrightnessExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs index e214c5a164..33efccecfb 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs index 4a3e460b85..3f05651df1 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs index f89540e245..e395e2778b 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/GrayscaleExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/GrayscaleExtensions.cs index 4125de8321..00b0f4bb59 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/GrayscaleExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/GrayscaleExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs index ef1fa2a6ec..d387fc7e3e 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs index 0642db849d..97acd1aa79 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/KodachromeExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/KodachromeExtensions.cs index eadbde7bc0..7810e7c5c9 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/KodachromeExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/KodachromeExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/LightnessExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/LightnessExtensions.cs index d68cb6aacb..f50021dd37 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/LightnessExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/LightnessExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs index 3f8a67feb3..5bff26f0c8 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs index 2cf6085f34..386fa5fca3 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs index ab75ea56b5..d2c05765bb 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs index f68c424bdc..f3f0a82ccc 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs index 629ba03e77..537d280d06 100644 --- a/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs b/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs index 72962a3f9f..a1e708993b 100644 --- a/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Normalization; diff --git a/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs index 21e244f0a3..10a5709590 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Overlays; diff --git a/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs index c3ce32e636..55fe83da02 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Overlays; diff --git a/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs index b53880fc12..47b05ffe90 100644 --- a/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Overlays; diff --git a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs index 45cff93982..fae6792760 100644 --- a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Processing/Extensions/Quantization/QuantizeExtensions.cs b/src/ImageSharp/Processing/Extensions/Quantization/QuantizeExtensions.cs index 86ccddd856..e160ee9210 100644 --- a/src/ImageSharp/Processing/Extensions/Quantization/QuantizeExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Quantization/QuantizeExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Quantization; diff --git a/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs index 984081dffe..5a357375b0 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs index 5fc8125ea8..0afc3bf17f 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs index de5296d83e..ce9f65e963 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs index f6b3c0c374..7fd1198d55 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs index 33a6fc36d6..f7e28cd73f 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/Extensions/Transforms/ResizeExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/ResizeExtensions.cs index 882b177214..ff70c8f744 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/ResizeExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/ResizeExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs index 395462ae33..7eac4d0fab 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs index 0e4ad4066c..09470a732b 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs index 77a46af0d9..e3efc8391f 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs index ee8f3854e8..d5adc2701d 100644 --- a/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Processing/FlipMode.cs b/src/ImageSharp/Processing/FlipMode.cs index 96cd38de4a..56b8300ab6 100644 --- a/src/ImageSharp/Processing/FlipMode.cs +++ b/src/ImageSharp/Processing/FlipMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/GrayscaleMode.cs b/src/ImageSharp/Processing/GrayscaleMode.cs index e42a2e6333..42a3c0ae3e 100644 --- a/src/ImageSharp/Processing/GrayscaleMode.cs +++ b/src/ImageSharp/Processing/GrayscaleMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/IImageProcessingContext.cs b/src/ImageSharp/Processing/IImageProcessingContext.cs index cb39766a94..8398f093ea 100644 --- a/src/ImageSharp/Processing/IImageProcessingContext.cs +++ b/src/ImageSharp/Processing/IImageProcessingContext.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.Processing.Processors; diff --git a/src/ImageSharp/Processing/IImageProcessingContextFactory.cs b/src/ImageSharp/Processing/IImageProcessingContextFactory.cs index 5394fac8b9..d843d453b0 100644 --- a/src/ImageSharp/Processing/IImageProcessingContextFactory.cs +++ b/src/ImageSharp/Processing/IImageProcessingContextFactory.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/IInternalImageProcessingContext{TPixel}.cs b/src/ImageSharp/Processing/IInternalImageProcessingContext{TPixel}.cs index a39483b0d9..38a1ef2020 100644 --- a/src/ImageSharp/Processing/IInternalImageProcessingContext{TPixel}.cs +++ b/src/ImageSharp/Processing/IInternalImageProcessingContext{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/KnownDitherings.cs b/src/ImageSharp/Processing/KnownDitherings.cs index bb968d2ef5..b5f6702320 100644 --- a/src/ImageSharp/Processing/KnownDitherings.cs +++ b/src/ImageSharp/Processing/KnownDitherings.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Dithering; diff --git a/src/ImageSharp/Processing/KnownFilterMatrices.cs b/src/ImageSharp/Processing/KnownFilterMatrices.cs index 268281e4fe..1dadccfd94 100644 --- a/src/ImageSharp/Processing/KnownFilterMatrices.cs +++ b/src/ImageSharp/Processing/KnownFilterMatrices.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Processing/KnownQuantizers.cs b/src/ImageSharp/Processing/KnownQuantizers.cs index e4a7a75d5f..1d3c09c515 100644 --- a/src/ImageSharp/Processing/KnownQuantizers.cs +++ b/src/ImageSharp/Processing/KnownQuantizers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Quantization; diff --git a/src/ImageSharp/Processing/KnownResamplers.cs b/src/ImageSharp/Processing/KnownResamplers.cs index 348c084071..694328207e 100644 --- a/src/ImageSharp/Processing/KnownResamplers.cs +++ b/src/ImageSharp/Processing/KnownResamplers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/OrientationMode.cs b/src/ImageSharp/Processing/OrientationMode.cs index ba55425b81..c6ef1a0354 100644 --- a/src/ImageSharp/Processing/OrientationMode.cs +++ b/src/ImageSharp/Processing/OrientationMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/PixelRowOperation.cs b/src/ImageSharp/Processing/PixelRowOperation.cs index 6857b24f19..1ce20d7b84 100644 --- a/src/ImageSharp/Processing/PixelRowOperation.cs +++ b/src/ImageSharp/Processing/PixelRowOperation.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs index 3558a94899..a09181fa81 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs index dd8833ad96..2d5918ec7d 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 17fb39df3e..a90f5f6f42 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs index 0d363689dd..559e6e4472 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs index 36cc7f6973..416f5ad07c 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs index e933978c20..0c9af05e5d 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs index 65aa81c608..3c2ec0ef36 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index cf97751bef..080e29a365 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index 92f7ab02d2..3ae74571f0 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs index fc80905ee4..400adb2671 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index f7439879e4..a4048e6a89 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index 4bbb15cbad..627cb7fbd6 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs index 34b085fc6e..191681c3e6 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessorHelpers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index 8201b8e239..70bd69f320 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs index 8bb60286a7..3325ea4958 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index 1b07589b51..df7abee68b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs index 472547765e..f422146b8d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs index 8ca548d975..bf4623ac84 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs index d566f6691c..a5ff500df7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs index cb77c8741f..92a848a1f8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs index 4854eae687..6c904a17fe 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs index 24c56363ae..6b35f120aa 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs index 90ed15aa33..65b2d2529c 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs index 423fc65917..bc0239a991 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/CompassKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs index 50d5bfafe4..6df09ca32b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/KayyaliKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs index 58568ce409..644e8d6689 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/KirschKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs index 8371212fe8..c36bedb917 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernelFactory.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs index f72e95ee8b..3c98c1673d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/LaplacianKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs index cae9ecb5bf..35c7f97162 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/PrewittKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs index 8ffd624d21..23b06a9876 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobertsCrossKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs index ba60bfdf64..89c576e8f9 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/RobinsonKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs index ec583862f7..70b4d195f0 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/ScharrKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs index 3dbd54a2c5..3918936fba 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Kernels/SobelKernels.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs index 7207f95c4b..2be8a8d301 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs index b147a87cc8..5079ecc230 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs index 663ebf0517..417fffec08 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs index 8b0cfc6ff3..95e6fdbdd8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelData.cs b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelData.cs index 561892683a..7a8e953d95 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelData.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelDataProvider.cs b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelDataProvider.cs index f7828fa9ef..a51f42bdc2 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelDataProvider.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurKernelDataProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Concurrent; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurParameters.cs b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurParameters.cs index 73688c5869..305b71e19e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurParameters.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Parameters/BokehBlurParameters.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs index 7fc54ff967..d1d9316cfa 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs index 74d5094f53..fdda446ac0 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs index 18ac906140..6c77bc904e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs index 24248204b6..e42c3b42b9 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs index 1ab56d1203..ac99d2d4dc 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Convolution { diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErroDither.KnownTypes.cs b/src/ImageSharp/Processing/Processors/Dithering/ErroDither.KnownTypes.cs index d39237a2cc..01f26fbbba 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErroDither.KnownTypes.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErroDither.KnownTypes.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Dithering { diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index e322afb8d2..75253fd378 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs index 8b0e1b8a89..5cb95ead81 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IDither.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; diff --git a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs index a8e08fa3fa..2a929c6fd8 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/IPaletteDitherImageProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs index f6026a64f7..83f7d6136c 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.KnownTypes.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Dithering { diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 0f5a7fb55c..811599e717 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherFactory.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherFactory.cs index 48aaa22d65..62b16203e3 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherFactory.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherFactory.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs index 5ce7ccec04..1c49707106 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index e0dd4eae18..de5a7ec306 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs index 34a0660495..81e99eecd9 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index fca896929f..96e7017600 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Effects/IPixelRowDelegate.cs b/src/ImageSharp/Processing/Processors/Effects/IPixelRowDelegate.cs index 626ffd7168..280c6e87b5 100644 --- a/src/ImageSharp/Processing/Processors/Effects/IPixelRowDelegate.cs +++ b/src/ImageSharp/Processing/Processors/Effects/IPixelRowDelegate.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index a816b0cb8b..47e482c78f 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs index 5ee1e40de0..3a943b2264 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor.cs index 3721afee32..5016657c15 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs index 71259a6188..8a70f1b742 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs index ba43ca6174..127f0eaa55 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs index 60f5d29b09..b3f7d51ec3 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelRowDelegateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelRowDelegateProcessor.cs index 6822daa424..2373c98f0f 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelRowDelegateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelRowDelegateProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Filters/AchromatomalyProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/AchromatomalyProcessor.cs index 0e6653d99b..01189f1b1e 100644 --- a/src/ImageSharp/Processing/Processors/Filters/AchromatomalyProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/AchromatomalyProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/AchromatopsiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/AchromatopsiaProcessor.cs index 10a201b1d7..6a86b463dd 100644 --- a/src/ImageSharp/Processing/Processors/Filters/AchromatopsiaProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/AchromatopsiaProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/BlackWhiteProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/BlackWhiteProcessor.cs index 425ae511f6..0e28c98469 100644 --- a/src/ImageSharp/Processing/Processors/Filters/BlackWhiteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/BlackWhiteProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/BrightnessProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/BrightnessProcessor.cs index 77862b3e3f..1b5dc05828 100644 --- a/src/ImageSharp/Processing/Processors/Filters/BrightnessProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/BrightnessProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/ContrastProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/ContrastProcessor.cs index 3fdeafde3e..f4dd63ad6f 100644 --- a/src/ImageSharp/Processing/Processors/Filters/ContrastProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/ContrastProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/DeuteranomalyProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/DeuteranomalyProcessor.cs index 7e1c0ca503..71638f2da2 100644 --- a/src/ImageSharp/Processing/Processors/Filters/DeuteranomalyProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/DeuteranomalyProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/DeuteranopiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/DeuteranopiaProcessor.cs index e4ed44e74e..730d710531 100644 --- a/src/ImageSharp/Processing/Processors/Filters/DeuteranopiaProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/DeuteranopiaProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs index 5cae98568a..148a34d95f 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index dee9d2ff62..a8c913a50a 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt601Processor.cs b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt601Processor.cs index 153a1a17c5..4dd2bb6af9 100644 --- a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt601Processor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt601Processor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs index 71d3f9c9cc..43d84b7048 100644 --- a/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/GrayscaleBt709Processor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs index 05d3cbdc7c..bdb5a6c1a8 100644 --- a/src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/HueProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/InvertProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/InvertProcessor.cs index 99b138033d..3437579290 100644 --- a/src/ImageSharp/Processing/Processors/Filters/InvertProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/InvertProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/KodachromeProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/KodachromeProcessor.cs index 30484f0590..96bdc59c7d 100644 --- a/src/ImageSharp/Processing/Processors/Filters/KodachromeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/KodachromeProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/LightnessProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/LightnessProcessor.cs index 49be3b6a67..3b4685f28a 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LightnessProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LightnessProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs index bb6ea51c12..6dd6c783b6 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs index 0706e9fc8d..81ff899b39 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Overlays; diff --git a/src/ImageSharp/Processing/Processors/Filters/OpacityProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/OpacityProcessor.cs index a537b8f606..eb11541817 100644 --- a/src/ImageSharp/Processing/Processors/Filters/OpacityProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/OpacityProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs index 95a099106f..8c0765bc7b 100644 --- a/src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/OpaqueProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs index 965a35be15..e098762c2d 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs index 470d553c2c..3b4bafc595 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Overlays; diff --git a/src/ImageSharp/Processing/Processors/Filters/ProtanomalyProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/ProtanomalyProcessor.cs index 1c01b608e5..e4bb904f28 100644 --- a/src/ImageSharp/Processing/Processors/Filters/ProtanomalyProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/ProtanomalyProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/ProtanopiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/ProtanopiaProcessor.cs index ec423bd9a5..f74a9f48f3 100644 --- a/src/ImageSharp/Processing/Processors/Filters/ProtanopiaProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/ProtanopiaProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/SaturateProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/SaturateProcessor.cs index 2cc40664b4..01ac91c955 100644 --- a/src/ImageSharp/Processing/Processors/Filters/SaturateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/SaturateProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/SepiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/SepiaProcessor.cs index 34af410671..4803bd9509 100644 --- a/src/ImageSharp/Processing/Processors/Filters/SepiaProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/SepiaProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/TritanomalyProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/TritanomalyProcessor.cs index a31e52c7e7..ba4b594782 100644 --- a/src/ImageSharp/Processing/Processors/Filters/TritanomalyProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/TritanomalyProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/Filters/TritanopiaProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/TritanopiaProcessor.cs index b622126f32..248e230dfa 100644 --- a/src/ImageSharp/Processing/Processors/Filters/TritanopiaProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/TritanopiaProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Filters { diff --git a/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs index 2f12e065be..4bd4549feb 100644 --- a/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/ICloningImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/ICloningImageProcessor{TPixel}.cs index 988d6d866e..999aad619f 100644 --- a/src/ImageSharp/Processing/Processors/ICloningImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/ICloningImageProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/IImageProcessor.cs b/src/ImageSharp/Processing/Processors/IImageProcessor.cs index 9d2e301de1..13d27ae8a8 100644 --- a/src/ImageSharp/Processing/Processors/IImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/IImageProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs index 4361936d1a..2e4a56e664 100644 --- a/src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs index 7e72c7bf03..a86f819f44 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs index 964a88d6a1..6b0fb68b8e 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs index 1fdb10661c..4fc33de0de 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Normalization { diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs index 1547de8acf..436f664419 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs index ff8a6b73d9..80a987828b 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Normalization { diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs index cce527ad43..8ff4f05270 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs index 3b984578b5..f6cbe1be88 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Normalization { diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs index 209135debb..c6327d3e06 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationMethod.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationMethod.cs index 641587c394..31f05b77fc 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationMethod.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationMethod.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Normalization { diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationOptions.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationOptions.cs index b55b725a6b..7e98cad56c 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationOptions.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Normalization { diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs index 031b121b91..a1d0a42da8 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs index ed0968f7c2..6067381fba 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 241ec1ebed..b147673b84 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs index 727e724698..af5029fa0a 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 5e0d1cbf7e..13efc879ed 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs index fbecbc37ce..49a3a2d984 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 3b16f8bc85..22b75fcb06 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs index 378009c400..daf18f8064 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs index d2bf06bcde..1f963017cd 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/DefaultPixelSamplingStrategy.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 775e0aa23f..6db0c2a174 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Concurrent; diff --git a/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs index 8ef05640aa..cd3c8a68e2 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/ExtensivePixelSamplingStrategy.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs b/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs index 6c2e3bd882..7b8151f089 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IPixelSamplingStrategy.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs index e59b9a6a7d..493c3e0ff0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs index 26c906f060..05bbb0b238 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 02e85167d8..b10c5bab5c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index 7fefda3f13..1f2c7ea511 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 38816a168d..4af8460ee6 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index 82ff572fa5..d2c5d1fedb 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs index bdaeb57f6d..2bfb5907f9 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index 9bc94831aa..72fb05d00c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs index ece3777e0e..e419e23cd3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Dithering; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerOptions.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerOptions.cs index 5c1daf183b..5a29a02c54 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerOptions.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Dithering; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs index 1fe69ea305..a623d37da4 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs index d95ed5aab9..586c8ff5ec 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Dithering; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs index 8f8e38dd9d..49e268d7e8 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Quantization { diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 0f1dff1811..1cab3996cc 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index 5e086feaa9..b7f21473de 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 9aa21e4dcd..52b32ed16b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Transforms { diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs index a366fd51de..657c2b28df 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs b/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs index 4d46540bcc..575ac5fbe2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/DegenerateTransformException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs index b2a50a9881..e2b42591c0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs index 8c91e19531..38e278bca4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/IResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/IResampler.cs index 55eebba4f7..509df8a42b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/IResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/IResampler.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs index 02df8282f0..7413cbafb3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/IResamplingTransformImageProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs index fec41dbffe..0a9660a66d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs index a3c8f71082..927d0361c4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor.cs index 534832d13f..552e2e1f1e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs index be1388dce4..b058c16892 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor.cs index b154aba88a..1b0f07c7c3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs index 470eafcd8d..ddb228b82a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs index 0a00cf8e9b..8ac4458278 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/LinearTransformUtilities.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs index f716ba701e..e787d361b2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs index f348721d7a..6f11b62d25 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs index b53e7b5c05..2708848ef8 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs index 43f67f7914..ce94e2a27e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs index 1bcfa5fd28..0760c6f699 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Linear/SkewProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs index b0a79766f2..7045833430 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs index 590d292e0b..1cc567166f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs index 8cdfcd8820..7ad238eaa3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CubicResampler.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs index 7eb6d111e0..fd21495fd6 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/LanczosResampler.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs index 9a78af82b4..27da022d9e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs index 345e567902..fe761f9d60 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs index 82f58a7c98..33b081b0fb 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs index de44d32e4b..6066efd1cd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index f3521ebed9..990ebc4821 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs index a79f60339d..e4b3a7ba0e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index 5390cbbd18..a619e23586 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 4e6e7a48c1..63135e47b7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing.Processors.Transforms { diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 09d95c8acd..a654dcc62d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs index 96e516e39e..f2fd4c628c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs index 5423eea88c..30317070c2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs index c1dce02be8..a9f63bd3c0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs index b474b43712..7c6069a5b6 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtilities.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs index b7e65b4cc0..f079c74902 100644 --- a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/src/ImageSharp/Processing/ResizeMode.cs b/src/ImageSharp/Processing/ResizeMode.cs index 142a926b30..b4d2d7d5c0 100644 --- a/src/ImageSharp/Processing/ResizeMode.cs +++ b/src/ImageSharp/Processing/ResizeMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/ResizeOptions.cs b/src/ImageSharp/Processing/ResizeOptions.cs index b54d2eae1c..bc978b7bea 100644 --- a/src/ImageSharp/Processing/ResizeOptions.cs +++ b/src/ImageSharp/Processing/ResizeOptions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/src/ImageSharp/Processing/RotateMode.cs b/src/ImageSharp/Processing/RotateMode.cs index c890f2bd67..7f9d4145e0 100644 --- a/src/ImageSharp/Processing/RotateMode.cs +++ b/src/ImageSharp/Processing/RotateMode.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/TaperCorner.cs b/src/ImageSharp/Processing/TaperCorner.cs index 395b171424..63b9a0fa16 100644 --- a/src/ImageSharp/Processing/TaperCorner.cs +++ b/src/ImageSharp/Processing/TaperCorner.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Processing/TaperSide.cs b/src/ImageSharp/Processing/TaperSide.cs index 226d11aed2..0fdcf37885 100644 --- a/src/ImageSharp/Processing/TaperSide.cs +++ b/src/ImageSharp/Processing/TaperSide.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Processing { diff --git a/src/ImageSharp/Properties/AssemblyInfo.cs b/src/ImageSharp/Properties/AssemblyInfo.cs index 225de354ae..36da831424 100644 --- a/src/ImageSharp/Properties/AssemblyInfo.cs +++ b/src/ImageSharp/Properties/AssemblyInfo.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // Redundant suppressing of SA1413 for Rider. [assembly: diff --git a/src/ImageSharp/ReadOrigin.cs b/src/ImageSharp/ReadOrigin.cs index f17bc82f18..76e40755bc 100644 --- a/src/ImageSharp/ReadOrigin.cs +++ b/src/ImageSharp/ReadOrigin.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp { diff --git a/tests/ImageSharp.Benchmarks/BenchmarkBase.cs b/tests/ImageSharp.Benchmarks/BenchmarkBase.cs index 87ed8fa423..412aec6f04 100644 --- a/tests/ImageSharp.Benchmarks/BenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/BenchmarkBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Benchmarks { diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs index 6be1998fba..fb799cb020 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs index e4723d3a06..170e99041e 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs index 82dd57c299..b04712f7e3 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs index b69dd36d78..025e6128ba 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs index 072bd53ed7..81cabe161c 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers; using System.IO; diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs index 2a6e215569..f30b19c162 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Drawing.Imaging; using System.IO; diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs index 58e3e01e39..a0fa12d673 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Drawing.Imaging; diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs index 70c85ef022..57ea71cf89 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Drawing.Imaging; using System.IO; diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs index 5c7a9e991b..5f3659c21c 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Drawing.Imaging; diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs index aedf9cd777..ceeed0f4e6 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs index 7bd1b80447..0a88cf1c9e 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Drawing.Imaging; using System.IO; diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs index f10eacb289..86eeff3842 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs b/tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs index 93f5bc8d85..b1f497129a 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Drawing; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs b/tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs index 4a9d709ee7..906b4c98ba 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // This file contains small, cheap and "unit test" benchmarks to test MultiImageBenchmarkBase. // Need this because there are no real test cases for the common benchmark utility stuff. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs index 55d66d488d..623cd5696b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs index 20f3e0d566..db95d043a8 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs index 05b7156ffc..3887bcac72 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs index 5dac391165..18573d45f8 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs index 32d838f8c4..6da398c103 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs index 51da291726..a13ae4de12 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Drawing; using System.IO; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs index 06492bc92d..cd2f411bda 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 1696623ef1..fd23688c54 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs index 6f3ea0e142..c398e26098 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DoubleBufferedStreams.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs index b64c86974a..f9ab79febb 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs index a710fc1965..cf01e5e615 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Drawing.Imaging; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs index ae32167a9f..a635f07471 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs index 4a3c88a281..4787f7d6b0 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Drawing; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs index 0d0e3212b1..99234922d4 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Drawing; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs index 1daf9b4d5a..b80dc33939 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index eafbc0fdeb..b8e00191f2 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Configs; using BenchmarkDotNet.Jobs; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs index dc1d21c14d..874eacdaba 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs index 1184bef2e0..a4412e0d60 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs index dfcc516468..2302db39d2 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs index c21c0abf57..c4e8e3e044 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index b57136a929..2e477b7ecf 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs index 3a69a6e246..c766b72e68 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs index 483ab61741..407fc3f26a 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs b/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs index 602e1137f0..c94eeafcc0 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs index 5ca5849173..8bf9fc9bc2 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs index 3f9d1648cb..a63b195052 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs index f82afaac47..f0d5fe49a9 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs index 59705a2023..f0b573ef6a 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.LookupTables.cs b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.LookupTables.cs index a2290ce1f7..dc2c3d8e5c 100644 --- a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.LookupTables.cs +++ b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.LookupTables.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Benchmarks { diff --git a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs index b11e389af7..3c3f2001f3 100644 --- a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs +++ b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs index b8e58a8c5a..86a119a6cd 100644 --- a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs +++ b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs b/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs index 5d3bc26bae..d0afb1d3e2 100644 --- a/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs +++ b/tests/ImageSharp.Benchmarks/Color/YcbCrToRgb.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Benchmarks { diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index fda98a097c..8af7d8f68a 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. #if Windows_NT using System.Security.Principal; diff --git a/tests/ImageSharp.Benchmarks/General/Array2D.cs b/tests/ImageSharp.Benchmarks/General/Array2D.cs index 92190e653b..40c6ab1206 100644 --- a/tests/ImageSharp.Benchmarks/General/Array2D.cs +++ b/tests/ImageSharp.Benchmarks/General/Array2D.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs b/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs index 41137e28be..63b45a5839 100644 --- a/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs +++ b/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs index fc0b149c1f..c800db7f8b 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs index 9644cbc7d3..10622f5cd5 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs index c01d988ee3..b4b379515b 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs index 145b98b0f4..61ebadee7a 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampVector4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs index 0ccde7a13a..9de30afba4 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs index e8cb8ca622..dba159d959 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs index b7eb01fcb5..1edf28516d 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/Round.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Round.cs index bb308d4805..6bb577e613 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/Round.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Round.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs b/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs index 2afa8753f8..9fa543edae 100644 --- a/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs +++ b/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs index 6d7c3c4236..255c1d909d 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 55527da188..4a5fd81447 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index 0b24276d33..bd29b3d830 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs index 93a27a5554..dfe581c500 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs index 6a59e993b8..3770aefe6f 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs index 80a2e80d22..73b35e10d2 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs index 699a4cf09d..b2edd9c9ad 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs index 7acb3ecfef..ae110fb4f9 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs index 4c8b987b2f..d0c4952664 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs index 4985206054..8e8a01864b 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index b325ec7c64..1af7080a34 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/StructCasting.cs b/tests/ImageSharp.Benchmarks/General/StructCasting.cs index ff89ad3ffe..6ac50e42c7 100644 --- a/tests/ImageSharp.Benchmarks/General/StructCasting.cs +++ b/tests/ImageSharp.Benchmarks/General/StructCasting.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.CompilerServices; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs b/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs index 80f4041620..45464eb467 100644 --- a/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs +++ b/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs index 41764b8160..fdffcc6e4a 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs index 8d842a0f51..c1c3ccffbb 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs index f103867cd8..42914e5c21 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs index 30dddf483a..19f4782281 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs index 61de537821..70be3d681a 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs index a800df405b..84f67536c3 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs index 5e9ffaae84..2122e1afa8 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Premultiply.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Premultiply.cs index cdc7cac2e8..d636109694 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/Premultiply.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Premultiply.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs index dc921bc420..2b52348be8 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.InteropServices; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs index 8fa0b5cfcf..44c8adab9b 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs index 3c79df494e..a5c8dafa2d 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs index 6d177588b4..396f754fe7 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization { diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs index beac94269d..faa905a661 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index 8953228f97..16b9a47fdc 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Benchmarks/Program.cs b/tests/ImageSharp.Benchmarks/Program.cs index 5caf238fb2..6ddfff7557 100644 --- a/tests/ImageSharp.Benchmarks/Program.cs +++ b/tests/ImageSharp.Benchmarks/Program.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Reflection; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Crop.cs b/tests/ImageSharp.Benchmarks/Samplers/Crop.cs index 8a5cccd68b..7abd8fa798 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Crop.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Crop.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Drawing; using System.Drawing.Drawing2D; diff --git a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs b/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs index 7718e72159..5c68e6b927 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs b/tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs index e53661c731..c817ab2070 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs b/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs index 711669b14e..57dbbd330e 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index 49a1bd5417..8af41d5a7d 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Drawing; using System.Drawing.Drawing2D; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs index 0610079fe3..8578d3b98e 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Skew.cs b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs index 7b8ec83a5b..e791385cfd 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Skew.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs b/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs index a94d0ed83f..318dfb6436 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs +++ b/tests/ImageSharp.Tests.ProfilingSandbox/Program.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Tests.Formats.Jpg; diff --git a/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs b/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs index 97731be94e..b50122628d 100644 --- a/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Advanced/AdvancedImageExtensionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs index 3fc4c56591..8ef69181f3 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs index c658227aeb..3c74c7f094 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs index 7f7c084e74..a93d5915a4 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Color/ColorTests.cs b/tests/ImageSharp.Tests/Color/ColorTests.cs index c689431f33..0ec10a77d8 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Color/ReferencePalette.cs b/tests/ImageSharp.Tests/Color/ReferencePalette.cs index d8403e27e2..25cabc46b8 100644 --- a/tests/ImageSharp.Tests/Color/ReferencePalette.cs +++ b/tests/ImageSharp.Tests/Color/ReferencePalette.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs index 4bba0ab039..cfec1ffa37 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs index 90c2c22446..dc09207cdc 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs index a6a5fa32ad..f810090882 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs index dbf64cb1d0..20d330a1ef 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs index 418893f350..785dd1a8ea 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs index 88196034bf..736275decb 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs index 3c77f132e3..d2f906e6ff 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs b/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs index dbf3fe6d8a..9dfcbd9c09 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs b/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs index e1386e1a09..6de0314c33 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs index 2046cdfdc5..83f7801c81 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs index 50d831fd90..eeba1b22fd 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs index 471610eba0..5b847b025b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs index 39011bb292..e52aadc4ef 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs index e007658328..af13c26fa0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs index 43300ab88c..37650c6729 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs index 4ab309fe14..177d434d5f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs index e7ff34f494..29e93f1df0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs index 844cda4760..e72a791030 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs index 74ed180f38..5f3a8f4995 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs index a3db00e804..826d7255ad 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs index fc202ccc96..5388bc6682 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs index 3e481d4f64..48e461d625 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs index 078ba44daf..0130e7cc67 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs index c5af017889..37c51356c2 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs index 49990fb908..0f39d5db2b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs index 924b45b4a0..c2d4b3f35b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs index 0991657310..759c2f7b3a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs index a7a819d1f7..572817174f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs index b83b861be8..7469d5d5f0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs index 932fdc4105..0aacd4a57b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs index 4d04418d99..c01b31255b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs index 3cdaa42792..c1fed0384c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs index e14d02faf4..3db47c54ae 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs index 0c62ffcc31..960f888de6 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs index 5566ce1b4c..25d1e6d259 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs index f130bb9470..6497a3b9eb 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs index 9e0af62eec..f21a10db83 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs index 68fe54b517..35cc082bbc 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs index 7c3e66f528..33d1e782d5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs index d42322336c..170365cc2d 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs index 8223ffdbce..29e306909f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs index e300049df0..943cf9f482 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs index 1c343afa29..0c9ee268f4 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs index 9a3cb8b010..5ce26d620a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs index 9e46024755..ad6cfc1b00 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs index 71b41e6cab..a6e47f3ef4 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs index 4737ba59f8..0e7fd10336 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs index 1193ccaa19..a2fec52be3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs index b1342c80c4..944647e10a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs index 49b99b7052..6dbce8ed70 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs index 42f00c51e0..1781ed74d5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs index f123617731..1a8b38a1cf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs index 761b9851e3..81208e5c3c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs index 2b0350cea1..a9edfef5b7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs index eda5db125f..7efeb4fb9f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs index 47f780789b..3089a2fe18 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs index 2fed3e9c55..95a50816eb 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs index 75634eb51e..bb364435a6 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs index d6d59ec076..8d4f829271 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs index dbb0c6e200..fdbab2f809 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs index 5fcc59090b..b62c74331b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs index 7ff80c170b..fc440c6216 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs index 8017302059..ff9498c125 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs index 3464fdbbde..3e3f48962d 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs index 26af5ddd30..ed5df4dc3a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs index dc40ee518e..4062f4df55 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs index 00569ced2e..549eb235d7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs index 104b1f4b22..06110af773 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs index 8a2cd1159e..bbd2dda6c4 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs index b01e3a854c..88c9fec451 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs index 8f9fef5e9e..8f09d3715e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs index 9adc94af7c..eb4c8c0e8b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs index 94879eee7a..1eec1d5b44 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs index bd870b01ac..e239f3efee 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs b/tests/ImageSharp.Tests/Colorspaces/HslTests.cs index 60cfa9761a..409428ffaa 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/HslTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs b/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs index d1d1d15c8a..f44b8d96af 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs b/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs index a657098f57..3ebf92cbb3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs index ef42e68bcc..9db4ab92cb 100644 --- a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs b/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs index f0c1471e0c..d954c770fd 100644 --- a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs index 17816aab18..2f0ae2f93d 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs b/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs index df96599945..9d48d239a3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs b/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs index f3e6f88f49..f802770e98 100644 --- a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; diff --git a/tests/ImageSharp.Tests/Common/ConstantsTests.cs b/tests/ImageSharp.Tests/Common/ConstantsTests.cs index 38d754d604..8795e90b8f 100644 --- a/tests/ImageSharp.Tests/Common/ConstantsTests.cs +++ b/tests/ImageSharp.Tests/Common/ConstantsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs index edaad4f51c..22240f14e9 100644 --- a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Text; diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index b6bfca4b53..78d47d8d4c 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Common/StreamExtensionsTests.cs b/tests/ImageSharp.Tests/Common/StreamExtensionsTests.cs index d47d5da8ef..5c09e71101 100644 --- a/tests/ImageSharp.Tests/Common/StreamExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Common/StreamExtensionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Common/Tuple8.cs b/tests/ImageSharp.Tests/Common/Tuple8.cs index 7c7f254db9..a8d3f10344 100644 --- a/tests/ImageSharp.Tests/Common/Tuple8.cs +++ b/tests/ImageSharp.Tests/Common/Tuple8.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Runtime.InteropServices; diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index a68baf93fb..368f472805 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs index 0aff95d994..d991fe7cfa 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageExtensionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs index d08d81899b..c721d15ffc 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Advanced; diff --git a/tests/ImageSharp.Tests/FileTestBase.cs b/tests/ImageSharp.Tests/FileTestBase.cs index 12f7636a2e..c862e8e931 100644 --- a/tests/ImageSharp.Tests/FileTestBase.cs +++ b/tests/ImageSharp.Tests/FileTestBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index f63fc0a16a..6d07d84df2 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index 235ecabf24..8f6125533f 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs index ccb57c35f1..232df080d8 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Formats.Bmp; diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs index 9818f9d41f..2082b7a8dd 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetadataTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index ca236e9146..a2d4ebd1ad 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 12d890357a..62d9bb2b98 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index bfe950d4fb..69e06490ce 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Formats; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetadataTests.cs index a3bc5d45c4..d3434864cd 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetadataTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Gif; using Xunit; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs index ddb5608daf..ed028fee8a 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetadataTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs index dc0da5e2db..de172ec517 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Gif; diff --git a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifImageDescriptorTests.cs b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifImageDescriptorTests.cs index 6a90c0c277..88f9c7d8ac 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifImageDescriptorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifImageDescriptorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Gif; diff --git a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifLogicalScreenDescriptorTests.cs b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifLogicalScreenDescriptorTests.cs index c6458d22ff..f9ad1f30d4 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifLogicalScreenDescriptorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifLogicalScreenDescriptorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Gif; diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index 9dba7179d9..cf94e468bb 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs index 8b0e89f59d..655f12c850 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/AdobeMarkerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index 169d3dd2dd..a18775ac15 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // Uncomment this to turn unit tests into benchmarks: // #define BENCHMARKING diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index b3c911f566..c85c83d2ca 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // Uncomment this to turn unit tests into benchmarks: // #define BENCHMARKING diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs index af8ba83c35..c8befba3af 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs index 683a79a8f4..3d8a3963ee 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/DCTTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs index 978ee7b2aa..908dc35ddf 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs index aebf80d082..9fb0b6ae29 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Metadata; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 27c612aee8..2bc404e5b6 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs index 57051a9d7b..d7c0b4e23a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index a01f4d46cd..356e3f18b3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index c2fc320aff..ce45f94857 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Formats; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs index 4ecf987e98..7e556c9979 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Progressive.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index a35bb177ce..77265c60e9 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 6cbdb83fcd..2c52baedac 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegFileMarkerTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegFileMarkerTests.cs index 42eea2708b..be5974cb45 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegFileMarkerTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegFileMarkerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs index 32481e1f51..47f6873115 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs index 50a2a44163..bd7abf8fca 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg; using Xunit; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs index a6f80f5581..bed4374bde 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/LibJpegToolsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs index 6e04610d5a..b08923b70b 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ParseStreamTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Text; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs index fb09065b0a..a938ee1b06 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ProfileResolverTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Text; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs index 82fcc368fc..87567751ad 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.AccurateDCT.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs index f8afb3d0be..3850b29e30 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // ReSharper disable InconsistentNaming using SixLabors.ImageSharp.Formats.Jpeg.Components; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs index ca40403805..852cc322b1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs index 0276e17085..c8a2cd1f73 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs index 3e125adac1..60fcca5232 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/SpectralJpegTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs index b7cf6a8406..5d4e6f9edb 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index b9526994eb..2ca6c1615c 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs index 0fce671e51..9f5e362b4d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs index 826335b652..bdc9e0776d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs index fc0540c64a..14041ca8dc 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.GT_FloatingPoint_DCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.GT_FloatingPoint_DCT.cs index 1adcf0bc07..fc1cb03a7d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.GT_FloatingPoint_DCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.GT_FloatingPoint_DCT.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs index 533ecaca1a..2abdf91fbe 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.LLM_FloatingPoint_DCT.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs index c11edb67c7..70a8db867d 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs index 4de576b256..90c778c4e4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/SpanExtensions.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/SpanExtensions.cs index 142e38dc0a..c90ed1b6e7 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/SpanExtensions.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/SpanExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs index 13685c8e8c..8b2282d086 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/VerifyJpeg.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Linq; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs index 61a5d8f1d8..450c2b2258 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Jpeg.Components; using Xunit; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs index 3a207722bd..fcffd399ed 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers.Binary; using System.Text; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index 6cefff95d4..afc6e05a6b 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers.Binary; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 72b27ec5d6..ed28a26460 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using Microsoft.DotNet.RemoteExecutor; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 2d5b2e25dd..7828134a75 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // ReSharper disable InconsistentNaming using System; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index bf42066002..a0a377348d 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs index a50b1059f8..1cd9fe5c2a 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Formats.Png; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngTextDataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngTextDataTests.cs index 72c0fd7ab0..4f250d07b9 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngTextDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngTextDataTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Formats.Png; diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index 6f886b73df..34bd52c8b8 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Microsoft.DotNet.RemoteExecutor; diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs index 6e0fa4a0ea..99b3fe8fe8 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs index 4797397e19..2b0b088a18 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs index 48171a77dc..3bbf1b1871 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/GlobalSuppressions.cs b/tests/ImageSharp.Tests/GlobalSuppressions.cs index 95fba0dffc..2b23eb6c1f 100644 --- a/tests/ImageSharp.Tests/GlobalSuppressions.cs +++ b/tests/ImageSharp.Tests/GlobalSuppressions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. diff --git a/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs b/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs index 9c02dd601e..b5e8a12e65 100644 --- a/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs +++ b/tests/ImageSharp.Tests/GraphicOptionsDefaultsExtensionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.Processing; diff --git a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs index 851aba6baf..1a267bf494 100644 --- a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs +++ b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 16a27a9cea..f2eb1be1ec 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Helpers/ParallelExecutionSettingsTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelExecutionSettingsTests.cs index fbe259d2bd..41ddaa0ed4 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelExecutionSettingsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelExecutionSettingsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Advanced; diff --git a/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs index 08d64a738d..5f7b311270 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs index fd1eb546b5..64a25c2272 100644 --- a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs +++ b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs index e2486fb4ae..6ab1cb2875 100644 --- a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs +++ b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Helpers/UnitConverterHelperTests.cs b/tests/ImageSharp.Tests/Helpers/UnitConverterHelperTests.cs index 57e280d938..1871203da0 100644 --- a/tests/ImageSharp.Tests/Helpers/UnitConverterHelperTests.cs +++ b/tests/ImageSharp.Tests/Helpers/UnitConverterHelperTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Common.Helpers; using Xunit; diff --git a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs index bc1ffda48f..89206dbcab 100644 --- a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/IO/DoubleBufferedStreamReaderTests.cs b/tests/ImageSharp.Tests/IO/DoubleBufferedStreamReaderTests.cs index 62e2048431..14fad2bd64 100644 --- a/tests/ImageSharp.Tests/IO/DoubleBufferedStreamReaderTests.cs +++ b/tests/ImageSharp.Tests/IO/DoubleBufferedStreamReaderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/IO/LocalFileSystemTests.cs b/tests/ImageSharp.Tests/IO/LocalFileSystemTests.cs index 07f1b5cd07..30a46b60a5 100644 --- a/tests/ImageSharp.Tests/IO/LocalFileSystemTests.cs +++ b/tests/ImageSharp.Tests/IO/LocalFileSystemTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Image/ImageCloneTests.cs b/tests/ImageSharp.Tests/Image/ImageCloneTests.cs index bc2eec79d1..fc709a2eeb 100644 --- a/tests/ImageSharp.Tests/Image/ImageCloneTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageCloneTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Advanced; diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs index 2b7c1e2c60..303801a078 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs index a05b428e15..cf92b42a3a 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.cs index d81defbcda..9fb1bf37a3 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs index 58d7d7981c..998aabc70b 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/Image/ImageRotationTests.cs b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs index 28196c0da1..84778e8457 100644 --- a/tests/ImageSharp.Tests/Image/ImageRotationTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs index 156e51578b..0a56dca09c 100644 --- a/tests/ImageSharp.Tests/Image/ImageSaveTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageSaveTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs index dcf4dcfe84..f923832abe 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.DetectFormat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs index 2be9504079..c7dbbc2d8f 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Identify.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; using SixLabors.ImageSharp.Formats; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs index d010f60236..5941854c14 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.ImageLoadTestBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs b/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs index 399652851c..87ca1fb95e 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_PassLocalConfiguration.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_PassLocalConfiguration.cs index cb3400758f..c3ee5b198d 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_PassLocalConfiguration.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_PassLocalConfiguration.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs index 4c6b92100e..8a7f87ff21 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FileSystemPath_UseDefaultConfiguration.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_PassLocalConfiguration.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_PassLocalConfiguration.cs index 2b1411fa63..7cee119837 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_PassLocalConfiguration.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_PassLocalConfiguration.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_UseGlobalConfiguration.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_UseGlobalConfiguration.cs index b8ed6e75b5..97ae94948b 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_UseGlobalConfiguration.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromBytes_UseGlobalConfiguration.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_PassLocalConfiguration.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_PassLocalConfiguration.cs index 4e91cfebce..dbe1410c27 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_PassLocalConfiguration.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_PassLocalConfiguration.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_ThrowsRightException.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_ThrowsRightException.cs index 171b681cec..d8d7129df3 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_ThrowsRightException.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_ThrowsRightException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_UseDefaultConfiguration.cs b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_UseDefaultConfiguration.cs index 0c722b4d66..ab3a87a315 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_UseDefaultConfiguration.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Load_FromStream_UseDefaultConfiguration.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.Save.cs b/tests/ImageSharp.Tests/Image/ImageTests.Save.cs index dc65ecfef9..99feb8177a 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.Save.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.Save.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index e0152558b5..f1aaf0ae37 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index 6bba8b15c7..54de9b55f7 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Advanced; diff --git a/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs b/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs index 7352ddd7df..cd66be363c 100644 --- a/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs +++ b/tests/ImageSharp.Tests/Image/LargeImageIntegrationTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs b/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs index cb09fa010c..1f6a3c6bf3 100644 --- a/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs +++ b/tests/ImageSharp.Tests/Image/MockImageFormatDetector.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Formats; diff --git a/tests/ImageSharp.Tests/Image/NoneSeekableStream.cs b/tests/ImageSharp.Tests/Image/NoneSeekableStream.cs index 10a531eafe..22358e173a 100644 --- a/tests/ImageSharp.Tests/Image/NoneSeekableStream.cs +++ b/tests/ImageSharp.Tests/Image/NoneSeekableStream.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/ImageInfoTests.cs b/tests/ImageSharp.Tests/ImageInfoTests.cs index bde5f7b6a5..07c7293a73 100644 --- a/tests/ImageSharp.Tests/ImageInfoTests.cs +++ b/tests/ImageSharp.Tests/ImageInfoTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Metadata; diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 8ddd9caf83..d9a44f8709 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Memory/Allocators/ArrayPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/ArrayPoolMemoryAllocatorTests.cs index 8db79fca08..a241921ecd 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/ArrayPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/ArrayPoolMemoryAllocatorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/Memory/Allocators/BufferExtensions.cs b/tests/ImageSharp.Tests/Memory/Allocators/BufferExtensions.cs index 9f8543fff0..933dfec746 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/BufferExtensions.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/BufferExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/Memory/Allocators/BufferTestSuite.cs b/tests/ImageSharp.Tests/Memory/Allocators/BufferTestSuite.cs index 6465e0b81d..391d654d6c 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/BufferTestSuite.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/BufferTestSuite.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs index 9e14bd1db6..18a2bf030d 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.InteropServices; diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index ab04b37000..c692f7c9da 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs index 59f3f5aa04..0eb4fe0ece 100644 --- a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs +++ b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; using Xunit; diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupIndex.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupIndex.cs index 555d641c7b..4e5ce8823f 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupIndex.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupIndex.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupIndexTests.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupIndexTests.cs index f0cc18f29f..a9a6d98606 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupIndexTests.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupIndexTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs index 298b5a93f5..1ce7af0d1d 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.CopyTo.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.CopyTo.cs index ab69a30770..acca894a0f 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.CopyTo.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.CopyTo.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.SwapOrCopyContent.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.SwapOrCopyContent.cs index c10fdc15de..a1f3f7edea 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.SwapOrCopyContent.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.SwapOrCopyContent.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.View.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.View.cs index 8884037a56..654c067344 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.View.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.View.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs index 15b07265f6..3522d5a92a 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTestsBase.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTestsBase.cs index 8dd28653c7..644e866654 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTestsBase.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTestsBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/Memory/TestStructs.cs b/tests/ImageSharp.Tests/Memory/TestStructs.cs index 858bb8e646..d95b4edf6d 100644 --- a/tests/ImageSharp.Tests/Memory/TestStructs.cs +++ b/tests/ImageSharp.Tests/Memory/TestStructs.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs index 746c0f3c72..000b247e2d 100644 --- a/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs +++ b/tests/ImageSharp.Tests/Metadata/ImageFrameMetadataTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Metadata; diff --git a/tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs index 60d791e91e..5e81e2d9c9 100644 --- a/tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs +++ b/tests/ImageSharp.Tests/Metadata/ImageMetadataTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 7069b03464..5b927e2f9e 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifReaderTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifReaderTests.cs index 85c9231fa9..d55fca3c56 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifReaderTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifReaderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs index 64219fce02..95f927de00 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Exif; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs index 7f52fb6cae..1949e3eaa2 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs index 495057455b..be5fb243ba 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Exif; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderCurvesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderCurvesTests.cs index 4ca7f84a57..69ad262204 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderCurvesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderCurvesTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs index 96c8975378..9f07d47594 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderMatrixTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderMatrixTests.cs index 8245d26e01..b7a0d8a131 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderMatrixTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderMatrixTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderMultiProcessElementTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderMultiProcessElementTests.cs index 412d5fc073..95ab5226c9 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderMultiProcessElementTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderMultiProcessElementTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderNonPrimitivesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderNonPrimitivesTests.cs index a050f38596..98cbbd4e93 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderNonPrimitivesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderNonPrimitivesTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderPrimitivesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderPrimitivesTests.cs index bd9eb1ea8d..70fe79baf3 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderPrimitivesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderPrimitivesTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Metadata.Profiles.Icc; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderTagDataEntryTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderTagDataEntryTests.cs index a18fb1ab88..e5fb6114a1 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderTagDataEntryTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderTagDataEntryTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderTests.cs index fc3502e3e3..b2f1c0ed44 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Metadata.Profiles.Icc; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterCurvesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterCurvesTests.cs index 39ebf33749..05f5a271b9 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterCurvesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterCurvesTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests.cs index 6245d8bb6e..27f8314bbe 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests1.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests1.cs index 15cd27b94f..1e40d9b7d2 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests1.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests1.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests2.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests2.cs index 7c301c754c..30f9537570 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests2.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterLutTests2.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterMatrixTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterMatrixTests.cs index 0873874afa..9a92cea956 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterMatrixTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterMatrixTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterMultiProcessElementTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterMultiProcessElementTests.cs index 2888958b07..248ae034a8 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterMultiProcessElementTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterMultiProcessElementTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterNonPrimitivesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterNonPrimitivesTests.cs index c88ea3a953..5d72e403b6 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterNonPrimitivesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterNonPrimitivesTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterPrimitivesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterPrimitivesTests.cs index 20e4a71419..83af8fd316 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterPrimitivesTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterPrimitivesTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Metadata.Profiles.Icc; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterTagDataEntryTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterTagDataEntryTests.cs index 85e11c8560..7dec70b6cd 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterTagDataEntryTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterTagDataEntryTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterTests.cs index 7249e03aa1..853dc4dafb 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataWriter/IccDataWriterTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs index 633c7c8230..5504a43318 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccProfileTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Metadata.Profiles.Icc; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccReaderTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccReaderTests.cs index 1502b8b30e..4a303723ed 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccReaderTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccReaderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccWriterTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccWriterTests.cs index c4ac921b10..a6cbe2accb 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccWriterTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/IccWriterTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/Various/IccProfileIdTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/Various/IccProfileIdTests.cs index 5c80ac36b6..0cdcfd6dfa 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/Various/IccProfileIdTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/Various/IccProfileIdTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; using Xunit; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs index 3baea45d62..cb1fdace86 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/IPTC/IptcProfileTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Numerics/RationalTests.cs b/tests/ImageSharp.Tests/Numerics/RationalTests.cs index 7b3bd86fc9..761543f892 100644 --- a/tests/ImageSharp.Tests/Numerics/RationalTests.cs +++ b/tests/ImageSharp.Tests/Numerics/RationalTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/Numerics/SignedRationalTests.cs b/tests/ImageSharp.Tests/Numerics/SignedRationalTests.cs index 2931ab3910..c171232d78 100644 --- a/tests/ImageSharp.Tests/Numerics/SignedRationalTests.cs +++ b/tests/ImageSharp.Tests/Numerics/SignedRationalTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs index 6b542badff..a1c9ac3413 100644 --- a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 74b9ef1c80..d4cb1b0029 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 1723497390..065d87b613 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 4dbd00cbbb..988e3f5dba 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 6ee14c0159..9d9a0dff2c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index b979eebdec..5c032d79f5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index e36d54b52e..8be964c66b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 487adc2412..688617bdf3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index b1ae7fd139..8d60a7021e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index 1712a6e1ee..10325e5109 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index c529e1b51b..38efe1ff5e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs index 179ba12b2d..07424602a1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs index f9bb084dee..d4fc794d08 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs index 3ad2dccdd2..08b054f63d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs index 40739c69a2..4fe322a6e5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 1533f9cf9a..62baa56ef7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 0ab7033983..6d52ea2d10 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index a726cee4e6..a5be4fc450 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 96334be02e..7ef933c6ef 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs index e2d370cc0e..4efb066ddf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs index a91ea09776..b8d9e50da4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders { diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs index 7831dc1242..e939761daf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats.PixelBlenders; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTestsTPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTestsTPixel.cs index f41fbc0226..67e70d98a6 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTestsTPixel.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTestsTPixel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs index 2ff5157b79..d93f72d0c1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs index 19623c3d8f..eb5382881c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats.Utils; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelConversionModifiersExtensionsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelConversionModifiersExtensionsTests.cs index 817c29aa1e..23bed6a010 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelConversionModifiersExtensionsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelConversionModifiersExtensionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs index 9a0f4d8acb..b3c6170590 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs index afcec79385..45a805ec00 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs index 1c966951fc..96d1f329c9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra5551OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra5551OperationsTests.cs index aa9b7bb1b8..b6af8ffa80 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra5551OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra5551OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L16OperationsTests.cs index 87aed91e76..4855351c35 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L16OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L16OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L8OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L8OperationsTests.cs index b2a1a2dc3a..6d02cbd3e2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L8OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.L8OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La16OperationsTests.cs index a17594af6a..4b19544094 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La16OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La16OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La32OperationsTests.cs index dce9342866..08ba9ce165 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.La32OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb24OperationsTests.cs index 37793911a2..39760bffad 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb24OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb24OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using Xunit; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs index 0a28db6b0a..634627b0b8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs index 1ecbaf3615..650196fba1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Buffers; using System.Numerics; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs index 6787602bb2..232152e637 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs index f9cc042a77..ed210f8a71 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index 9d48675f16..be31c7f76d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index ad45b0771f..2bfd9e99d2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index 06e3d59482..8634dfe00f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 6ab7b9c954..6c887aaadb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 7b3f71985c..cee4ecd925 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 6656ba19c2..b64aeeff28 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 34ec0bdef0..0b29d41428 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index 3a2841bb3b..99d766ad6a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 45f65eb4b7..0d97218540 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 54abf0db08..6eff0f5b81 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 162775a25f..0a85a94c47 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Primitives/ColorMatrixTests.cs b/tests/ImageSharp.Tests/Primitives/ColorMatrixTests.cs index 6b9b14bbfe..5df77bb673 100644 --- a/tests/ImageSharp.Tests/Primitives/ColorMatrixTests.cs +++ b/tests/ImageSharp.Tests/Primitives/ColorMatrixTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs index d515b21a9d..dc73ccf76a 100644 --- a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs +++ b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using Xunit; diff --git a/tests/ImageSharp.Tests/Primitives/PointFTests.cs b/tests/ImageSharp.Tests/Primitives/PointFTests.cs index 2bb4cc6dda..1cc4689656 100644 --- a/tests/ImageSharp.Tests/Primitives/PointFTests.cs +++ b/tests/ImageSharp.Tests/Primitives/PointFTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/tests/ImageSharp.Tests/Primitives/PointTests.cs b/tests/ImageSharp.Tests/Primitives/PointTests.cs index 8e86c72188..7d4aea01e2 100644 --- a/tests/ImageSharp.Tests/Primitives/PointTests.cs +++ b/tests/ImageSharp.Tests/Primitives/PointTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/tests/ImageSharp.Tests/Primitives/RectangleFTests.cs b/tests/ImageSharp.Tests/Primitives/RectangleFTests.cs index f0ba757160..774f7c3791 100644 --- a/tests/ImageSharp.Tests/Primitives/RectangleFTests.cs +++ b/tests/ImageSharp.Tests/Primitives/RectangleFTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/tests/ImageSharp.Tests/Primitives/RectangleTests.cs b/tests/ImageSharp.Tests/Primitives/RectangleTests.cs index acfbe9e61c..2e306842c1 100644 --- a/tests/ImageSharp.Tests/Primitives/RectangleTests.cs +++ b/tests/ImageSharp.Tests/Primitives/RectangleTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/tests/ImageSharp.Tests/Primitives/SizeFTests.cs b/tests/ImageSharp.Tests/Primitives/SizeFTests.cs index 8cda5d4ebf..2bdbe72b31 100644 --- a/tests/ImageSharp.Tests/Primitives/SizeFTests.cs +++ b/tests/ImageSharp.Tests/Primitives/SizeFTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/tests/ImageSharp.Tests/Primitives/SizeTests.cs b/tests/ImageSharp.Tests/Primitives/SizeTests.cs index 4aea060366..4dddb63d42 100644 --- a/tests/ImageSharp.Tests/Primitives/SizeTests.cs +++ b/tests/ImageSharp.Tests/Primitives/SizeTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs index 953563006b..766f78e955 100644 --- a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs +++ b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.ComponentModel.DataAnnotations; using SixLabors.ImageSharp.Advanced; diff --git a/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs b/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs index f992ac35b3..674d706b8a 100644 --- a/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs +++ b/tests/ImageSharp.Tests/Processing/Binarization/AdaptiveThresholdTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs b/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs index 34165319af..b929411620 100644 --- a/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs +++ b/tests/ImageSharp.Tests/Processing/Binarization/BinaryThresholdTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Binarization; diff --git a/tests/ImageSharp.Tests/Processing/Binarization/OrderedDitherFactoryTests.cs b/tests/ImageSharp.Tests/Processing/Binarization/OrderedDitherFactoryTests.cs index 5d550a595d..ad48c299c1 100644 --- a/tests/ImageSharp.Tests/Processing/Binarization/OrderedDitherFactoryTests.cs +++ b/tests/ImageSharp.Tests/Processing/Binarization/OrderedDitherFactoryTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing.Processors.Dithering; diff --git a/tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs index b67c482dd2..50c4169fc7 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/BoxBlurTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs index e0b1e1bbb1..33c83ad63b 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/DetectEdgesTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs index 8d17bc3564..903dfdfa89 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/GaussianBlurTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs b/tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs index 5849f1a98e..f686a889c5 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/GaussianSharpenTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/tests/ImageSharp.Tests/Processing/Convolution/Processors/LaplacianKernelFactoryTests.cs b/tests/ImageSharp.Tests/Processing/Convolution/Processors/LaplacianKernelFactoryTests.cs index ff20e3b9d2..23c89b5bc1 100644 --- a/tests/ImageSharp.Tests/Processing/Convolution/Processors/LaplacianKernelFactoryTests.cs +++ b/tests/ImageSharp.Tests/Processing/Convolution/Processors/LaplacianKernelFactoryTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Processing.Processors.Convolution; diff --git a/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs b/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs index 0cc8db6518..b97d91c445 100644 --- a/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs +++ b/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs index 34b99461d3..412e7393cf 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/BackgroundColorTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Overlays; diff --git a/tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs b/tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs index 797423394e..b63bad4e88 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/OilPaintTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Effects; diff --git a/tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs b/tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs index f449b8cb50..9d359d77b5 100644 --- a/tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs +++ b/tests/ImageSharp.Tests/Processing/Effects/PixelateTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Effects; diff --git a/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs b/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs index cd4d782792..b3cc948941 100644 --- a/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs +++ b/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Linq; diff --git a/tests/ImageSharp.Tests/Processing/Filters/BlackWhiteTest.cs b/tests/ImageSharp.Tests/Processing/Filters/BlackWhiteTest.cs index 41e60c84ae..3f8cb45ea7 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/BlackWhiteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/BlackWhiteTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/BrightnessTest.cs b/tests/ImageSharp.Tests/Processing/Filters/BrightnessTest.cs index a8b5b36435..384d01b4c9 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/BrightnessTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/BrightnessTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/ColorBlindnessTest.cs b/tests/ImageSharp.Tests/Processing/Filters/ColorBlindnessTest.cs index 70c78ec81a..efa6128ac2 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/ColorBlindnessTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/ColorBlindnessTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs b/tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs index bf2d6823ad..4ed75aba84 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/ContrastTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/Processing/Filters/FilterTest.cs b/tests/ImageSharp.Tests/Processing/Filters/FilterTest.cs index 46fa611686..332ecee0ff 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/FilterTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/FilterTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/Processing/Filters/GrayscaleTest.cs b/tests/ImageSharp.Tests/Processing/Filters/GrayscaleTest.cs index 9afaf16fd4..407d10717d 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/GrayscaleTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/GrayscaleTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Processing/Filters/HueTest.cs b/tests/ImageSharp.Tests/Processing/Filters/HueTest.cs index 8aef5415cd..a3d004e403 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/HueTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/HueTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/InvertTest.cs b/tests/ImageSharp.Tests/Processing/Filters/InvertTest.cs index 7e8b76458b..8f6dba6625 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/InvertTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/InvertTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/KodachromeTest.cs b/tests/ImageSharp.Tests/Processing/Filters/KodachromeTest.cs index c171a12431..64973b01f3 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/KodachromeTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/KodachromeTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/LightnessTest.cs b/tests/ImageSharp.Tests/Processing/Filters/LightnessTest.cs index 29d1d63e62..3554150274 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/LightnessTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/LightnessTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs b/tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs index 6cb38e2fe9..f51bea16f0 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/LomographTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Tests.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Filters/OpacityTest.cs b/tests/ImageSharp.Tests/Processing/Filters/OpacityTest.cs index 89e7d5ef9a..6771ec2714 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/OpacityTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/OpacityTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs b/tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs index 346df03799..985b1d9a3c 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/PolaroidTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/SaturateTest.cs b/tests/ImageSharp.Tests/Processing/Filters/SaturateTest.cs index 8ae4107687..f7b4f81770 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/SaturateTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/SaturateTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/Filters/SepiaTest.cs b/tests/ImageSharp.Tests/Processing/Filters/SepiaTest.cs index 02e5f42763..9460b6099b 100644 --- a/tests/ImageSharp.Tests/Processing/Filters/SepiaTest.cs +++ b/tests/ImageSharp.Tests/Processing/Filters/SepiaTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Filters; diff --git a/tests/ImageSharp.Tests/Processing/ImageOperationTests.cs b/tests/ImageSharp.Tests/Processing/ImageOperationTests.cs index 0638441783..b7c659ab74 100644 --- a/tests/ImageSharp.Tests/Processing/ImageOperationTests.cs +++ b/tests/ImageSharp.Tests/Processing/ImageOperationTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs b/tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs index 1c6a1c7ddc..de3bbb7c70 100644 --- a/tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs +++ b/tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Moq; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Normalization/HistogramEqualizationTests.cs b/tests/ImageSharp.Tests/Processing/Normalization/HistogramEqualizationTests.cs index 5e2b7062e7..681d6e3b4e 100644 --- a/tests/ImageSharp.Tests/Processing/Normalization/HistogramEqualizationTests.cs +++ b/tests/ImageSharp.Tests/Processing/Normalization/HistogramEqualizationTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs index 0336b231b5..ddafa0df9f 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/GlowTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs index 5d41c58cea..1c9732a705 100644 --- a/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Overlays/VignetteTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Overlays; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryDitherTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryDitherTests.cs index e718df4a26..b1113f5fed 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryDitherTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryDitherTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs index 3801a48883..909105badd 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Binarization/BinaryThresholdTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/Basic1ParameterConvolutionTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/Basic1ParameterConvolutionTests.cs index bd574c916b..9a9fec4fe9 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/Basic1ParameterConvolutionTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/Basic1ParameterConvolutionTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs index 9dc1350166..1664693e99 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BoxBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BoxBlurTest.cs index 66e9ba2df3..f25850e83c 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BoxBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BoxBlurTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs index 3d1e378b16..f6efeb2d64 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianBlurTest.cs index d1a3baa5a3..02678c0fc8 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianBlurTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianSharpenTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianSharpenTest.cs index 535520cb8b..1906d283e1 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianSharpenTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianSharpenTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs index 2ae9263926..71e707c542 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs index 88ebec4e2c..b716bccc32 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Effects/BackgroundColorTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Effects/OilPaintTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Effects/OilPaintTest.cs index 4eeebc3a0c..5b5c32d8fa 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Effects/OilPaintTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Effects/OilPaintTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelShaderTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelShaderTest.cs index dd4abfc76a..64dc4d7a16 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelShaderTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelShaderTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelateTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelateTest.cs index d7cee311d1..278f703e8a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelateTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelateTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/BlackWhiteTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/BlackWhiteTest.cs index 86518b015a..aadcdd0a0c 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/BlackWhiteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/BlackWhiteTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/BrightnessTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/BrightnessTest.cs index bb52731bb7..438a92b8ff 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/BrightnessTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/BrightnessTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/ColorBlindnessTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/ColorBlindnessTest.cs index 5c6a298225..d71a6d9e91 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/ColorBlindnessTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/ColorBlindnessTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/ContrastTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/ContrastTest.cs index 1758db8dd8..d2edfc9350 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/ContrastTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/ContrastTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs index ae9abed7f6..a14460fafb 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/FilterTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/GrayscaleTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/GrayscaleTest.cs index 2352a4dce7..04dabec821 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/GrayscaleTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/GrayscaleTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/HueTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/HueTest.cs index 9b96653b88..dd008957b6 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/HueTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/HueTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/InvertTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/InvertTest.cs index cb7a403f91..d88fb9c4e1 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/InvertTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/InvertTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/KodachromeTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/KodachromeTest.cs index 04e86c955b..c6e2e78d55 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/KodachromeTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/KodachromeTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/LightnessTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/LightnessTest.cs index 8b77f902df..2e10c8c587 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/LightnessTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/LightnessTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/LomographTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/LomographTest.cs index 65e616dca3..bf535decde 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/LomographTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/LomographTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/OpacityTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/OpacityTest.cs index bd73361192..4014de6355 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/OpacityTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/OpacityTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/PolaroidTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/PolaroidTest.cs index 26dac75321..ba8ccf2a14 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/PolaroidTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/PolaroidTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/SaturateTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/SaturateTest.cs index 4be11a72cc..e6d519ad0b 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/SaturateTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/SaturateTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Filters/SepiaTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Filters/SepiaTest.cs index fa43cb15af..4d822288c8 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Filters/SepiaTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Filters/SepiaTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs index e6a960f9e2..e40493ac94 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Overlays/GlowTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs b/tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs index 88cd6688a5..cc48fd40a4 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Overlays/OverlayTestBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs index 470f48f781..8572e754f9 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Overlays/VignetteTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs index dd27164f31..fa6f27c921 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs index acc9a0e012..b33a245151 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs index bcbb60e798..c498b9bc74 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs index d78e9254ca..48cb133b2c 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs index 2de903d664..4bf6e91b21 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs index a4fec9fd92..51a11919ce 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Metadata.Profiles.Exif; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs index f0eef3afd1..1fd7ecf0f9 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs index 6ba795e560..ea85c4ef5c 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/EntropyCropTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs index ae53afd67f..ff15b28599 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs index 28833248c0..54abb79904 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/PadTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResamplerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResamplerTests.cs index d3025d9118..62b7cfa686 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResamplerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResamplerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeHelperTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeHelperTests.cs index cdc96f042a..42f029a00f 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeHelperTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeHelperTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs index 3d08cf1a4c..405bf9fe5b 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Linq; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs index 8dbc056550..f61b4e18c4 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 3f323000ab..aec0d2a1f6 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateFlipTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateFlipTests.cs index 04647c019a..b9c3502c8a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateFlipTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateFlipTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateTests.cs index cf7c0c54ba..79c259c1e5 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTests.cs index 0720bcfa2d..7591f23844 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs index 70b5be73e5..bf3d8e3ff0 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs index 16ff9419ae..4eca2ccbd6 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs index edf6a64403..24d94f5b97 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/EntropyCropTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/EntropyCropTest.cs index 8525528c7e..537d619da3 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/EntropyCropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/EntropyCropTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/FlipTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/FlipTests.cs index 59d226ef5b..d6264540c6 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/FlipTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/FlipTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs index db1e76ae5d..2fc9c8aea6 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/PadTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs index 22388a0ac1..6c6e4a0152 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index c702aebe4b..afe08f6f60 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs index e7b92b7b32..1f6da58f1c 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ResizeTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/RotateFlipTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/RotateFlipTests.cs index 327b14bcd5..ebd17a9c30 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/RotateFlipTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/RotateFlipTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/RotateTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/RotateTests.cs index b1831f96e8..42aa8aadb7 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/RotateTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/RotateTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/SkewTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/SkewTest.cs index 66a157a8ad..fe22e7b87b 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/SkewTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/SkewTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs index 8c75cea7fd..8b64492c05 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs index 9f8034fa37..8d2b493a10 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index 0b63d63775..7d16bdf33b 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs index 858607a02f..87c0348ec2 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs index 34a1eaa30d..9579b24c63 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. // Uncomment to enable local profiling benchmarks. DO NOT PUSH TO MAIN! // #define PROFILING diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs index ba5eb532b2..26c34ba00d 100644 --- a/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs index 2b81e721fb..a4e022a1ac 100644 --- a/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs +++ b/tests/ImageSharp.Tests/Quantization/PixelSamplingStrategyTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index 067604f82a..7ec63064c3 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index 2a9280d6d6..0457de35ed 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using SixLabors.ImageSharp.Advanced; diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataArray.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataArray.cs index a4d5e7c133..41925c2e08 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataArray.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataArray.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Tests { diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataCurves.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataCurves.cs index 837674e708..9b6e1eb232 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataCurves.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataCurves.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using SixLabors.ImageSharp.Metadata.Profiles.Icc; diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataLut.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataLut.cs index 31f368cecc..e84f393c29 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataLut.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataLut.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs index 3bc787b344..1f55586597 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMatrix.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMultiProcessElements.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMultiProcessElements.cs index d7f9dd877a..913d1f5c64 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMultiProcessElements.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataMultiProcessElements.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Metadata.Profiles.Icc; diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs index 91f81cb433..d0e5eb21e1 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataNonPrimitives.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Globalization; diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs index c7b856a601..43c5958987 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataPrimitives.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Tests { diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs index 671edcfae0..4aa4d48e25 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs index bfe7d94b11..7df3ed21de 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataTagDataEntry.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Globalization; using System.Numerics; diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index bd185fa6b2..91f1dbe0e6 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Concurrent; diff --git a/tests/ImageSharp.Tests/TestFileSystem.cs b/tests/ImageSharp.Tests/TestFileSystem.cs index 9211e70f79..7779e8d6e5 100644 --- a/tests/ImageSharp.Tests/TestFileSystem.cs +++ b/tests/ImageSharp.Tests/TestFileSystem.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestFontUtilities.cs b/tests/ImageSharp.Tests/TestFontUtilities.cs index e087516c68..af648431fe 100644 --- a/tests/ImageSharp.Tests/TestFontUtilities.cs +++ b/tests/ImageSharp.Tests/TestFontUtilities.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.IO; diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 783d6fa48b..f3f4daa55e 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index e18ef3eef5..8815d83674 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Linq; diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index eff29555c8..ab7631066c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Numerics; diff --git a/tests/ImageSharp.Tests/TestUtilities/ArrayHelper.cs b/tests/ImageSharp.Tests/TestUtilities/ArrayHelper.cs index eceecb2c83..8dcc906409 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ArrayHelper.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ArrayHelper.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Linq; diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/GroupOutputAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/GroupOutputAttribute.cs index 3287311bf1..65832660b0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/GroupOutputAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/GroupOutputAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Tests { diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/ImageDataAttributeBase.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/ImageDataAttributeBase.cs index 85b178c733..f945feafaa 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/ImageDataAttributeBase.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/ImageDataAttributeBase.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithBasicTestPatternImagesAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithBasicTestPatternImagesAttribute.cs index 1e4324e046..398963e635 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithBasicTestPatternImagesAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithBasicTestPatternImagesAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Reflection; diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithBlankImagesAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithBlankImagesAttribute.cs index 051bfecdcf..cbd61e0521 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithBlankImagesAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithBlankImagesAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Reflection; diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithFileAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithFileAttribute.cs index e896c18546..74c7b38515 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithFileAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithFileAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Reflection; diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithFileCollectionAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithFileCollectionAttribute.cs index 1702513898..98ad544246 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithFileCollectionAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithFileCollectionAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithMemberFactoryAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithMemberFactoryAttribute.cs index 60c8c8cefc..02b2c7d623 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithMemberFactoryAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithMemberFactoryAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs index 5c67b5d138..0eb1b22d6e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Reflection; diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithTestPatternImagesAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithTestPatternImagesAttribute.cs index 0f00f1d86d..9c03c99836 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithTestPatternImagesAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithTestPatternImagesAttribute.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Reflection; diff --git a/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs b/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs index d7c54f35f2..89264bdbe2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs b/tests/ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs index 248755ea36..8d06c949a8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/GraphicsOptionsComparer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 9b7ebe34a0..e1ef383f39 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDifferenceIsOverThresholdException.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDifferenceIsOverThresholdException.cs index 626b698e1c..005ae5825d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDifferenceIsOverThresholdException.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDifferenceIsOverThresholdException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDimensionsMismatchException.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDimensionsMismatchException.cs index df1c1837b2..2b4b1963ca 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDimensionsMismatchException.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImageDimensionsMismatchException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImagesSimilarityException.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImagesSimilarityException.cs index d84f1c358a..d0deed371a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImagesSimilarityException.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/Exceptions/ImagesSimilarityException.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs index 76c018f066..76ee3d501a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs index 2faeacf683..0e6271513f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/PixelDifference.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/PixelDifference.cs index 6452bc581a..2c1363a071 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/PixelDifference.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/PixelDifference.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 36da984533..9ab2ce2a34 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs index 1025ed9a15..0cd25b10fd 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BlankProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BlankProvider.cs index b8ad5c5069..1e3b938748 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BlankProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BlankProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs index 48d7b80fbe..4b7d1b89f1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Concurrent; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/ITestImageProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/ITestImageProvider.cs index 199cc43166..762ffdb052 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/ITestImageProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/ITestImageProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. namespace SixLabors.ImageSharp.Tests { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/MemberMethodProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/MemberMethodProvider.cs index 45cf570647..4bbe4dc784 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/MemberMethodProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/MemberMethodProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Linq; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 1316473013..54a4877e60 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs index c652b32af3..606e12adaa 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Reflection; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index 47b6473296..dda7595cfc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index e08dff5255..386a0477ff 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/MeasureFixture.cs b/tests/ImageSharp.Tests/TestUtilities/MeasureFixture.cs index b01ece7ba3..a04e5384e4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/MeasureFixture.cs +++ b/tests/ImageSharp.Tests/TestUtilities/MeasureFixture.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs index 9d3427a069..c76934383a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs +++ b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 4708d70b0d..a146e260c6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index eb6f5e8c53..92c4cecd68 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs index 254112339c..05a1fbf849 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs index 563fe2cb3d..34bec526be 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Drawing.Imaging; using System.IO; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 7c29ac4db0..27088d9282 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Numerics; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index d49c34efd9..592c47f9c0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs index 4152d3bc66..f2e9fca5c1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Diagnostics; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index fbdb512dea..f643f90dae 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs index dd928cb755..709e9755d7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs b/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs index 3fd5f6e37b..7e936fb653 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestMemoryManager.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs index ba146b9e4b..d4c63c0119 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestType.cs b/tests/ImageSharp.Tests/TestUtilities/TestType.cs index 7643fb321e..c950b19b5d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestType.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestType.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 8af20a94fd..5743682f6c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestVector4.cs b/tests/ImageSharp.Tests/TestUtilities/TestVector4.cs index 8677184e32..484ec021b6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestVector4.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestVector4.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Numerics; using Xunit.Abstractions; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/BasicSerializerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/BasicSerializerTests.cs index 5039f0154f..4798e953a7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/BasicSerializerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/BasicSerializerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Tests.TestUtilities; using Xunit; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/GroupOutputTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/GroupOutputTests.cs index f411e9b08e..6bf435b513 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/GroupOutputTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/GroupOutputTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.IO; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ImageComparerTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ImageComparerTests.cs index b977ca022c..6464d0af44 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/ImageComparerTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ImageComparerTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; using System.Linq; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs index 6083b1faef..511fd1cc23 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using Xunit; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs index 9f9ea44f9f..31681e442a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs index 4c0d5758fe..dd777ba6fd 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 160b1fe407..8431b85569 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.IO; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageExtensionsTests.cs index 30f7f1f161..0a48c45550 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageExtensionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 498f3edca5..0390457a0e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Concurrent; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs index 821370b7a3..27f43d0046 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; diff --git a/tests/ImageSharp.Tests/VectorAssert.cs b/tests/ImageSharp.Tests/VectorAssert.cs index ba82eb1ac8..92bc1e45d2 100644 --- a/tests/ImageSharp.Tests/VectorAssert.cs +++ b/tests/ImageSharp.Tests/VectorAssert.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Collections.Generic; From 0f581ab5e6c763edc61603b27fdf5c4a5066a4c7 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 1 May 2020 09:19:23 +0200 Subject: [PATCH 199/213] Remove not needed image parameter from CalculateBitDepth --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 ++-- src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index d8509548ad..12ffb2cfcf 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -227,12 +227,12 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.options.MakeTransparentBlack) { quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, clonedImage); - this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, clonedImage, quantized); + this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, quantized); } else { quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, image); - this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, image, quantized); + this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, quantized); } return quantized; diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs index 3f490ca6f8..3a8e528cc0 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs @@ -89,11 +89,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The type of the pixel. /// The options. - /// The image. /// The quantized frame. public static byte CalculateBitDepth( PngEncoderOptions options, - Image image, IndexedImageFrame quantizedFrame) where TPixel : unmanaged, IPixel { From bc7eb2791d36d5c20ee0be6f38ba3001b7545067 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 1 May 2020 10:16:02 +0200 Subject: [PATCH 200/213] Add IgnoreMetadata to the png encoder options --- .../Formats/Png/IPngEncoderOptions.cs | 8 ++- src/ImageSharp/Formats/Png/PngChunkFilter.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoder.cs | 15 +++--- .../Formats/Png/PngEncoderOptions.cs | 8 +-- .../Formats/Png/PngEncoderOptionsHelpers.cs | 5 ++ .../Formats/Png/PngEncoderTests.Chunks.cs | 52 +++++++++++++++++++ 6 files changed, 76 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index e5d0b09cf7..770afa3c57 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -59,7 +59,13 @@ namespace SixLabors.ImageSharp.Formats.Png PngInterlaceMode? InterlaceMethod { get; } /// - /// Gets chunk filter method. + /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. + /// When set to true, all ancillary chunks will be skipped. + /// + bool IgnoreMetadata { get; } + + /// + /// Gets the chunk filter method. This allows to filter ancillary chunks. /// PngChunkFilter? ChunkFilter { get; } diff --git a/src/ImageSharp/Formats/Png/PngChunkFilter.cs b/src/ImageSharp/Formats/Png/PngChunkFilter.cs index 04f27fb73b..31d3012a6d 100644 --- a/src/ImageSharp/Formats/Png/PngChunkFilter.cs +++ b/src/ImageSharp/Formats/Png/PngChunkFilter.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Formats.Png ExcludeTextChunks = 1 << 3, /// - /// All possible optimizations. + /// All ancillary chunks will be excluded. /// ExcludeAll = ~None } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 53cec6e4ee..062e56c1d3 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -34,22 +34,19 @@ namespace SixLabors.ImageSharp.Formats.Png /// public IQuantizer Quantizer { get; set; } - /// - /// Gets or sets the transparency threshold. - /// + /// public byte Threshold { get; set; } = byte.MaxValue; /// public PngInterlaceMode? InterlaceMethod { get; set; } - /// - /// Gets or sets the chunk filter. This can be used to exclude some ancillary chunks from being written. - /// + /// public PngChunkFilter? ChunkFilter { get; set; } - /// - /// Gets or sets a value indicating whether fully transparent pixels should be converted to black pixels. - /// + /// + public bool IgnoreMetadata { get; set; } + + /// public bool MakeTransparentBlack { get; set; } /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index 2b43edd128..d0eb1a843d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -30,6 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.Threshold = source.Threshold; this.InterlaceMethod = source.InterlaceMethod; this.ChunkFilter = source.ChunkFilter; + this.IgnoreMetadata = source.IgnoreMetadata; this.MakeTransparentBlack = source.MakeTransparentBlack; } @@ -60,11 +61,12 @@ namespace SixLabors.ImageSharp.Formats.Png /// public PngInterlaceMode? InterlaceMethod { get; set; } - /// - /// Gets or sets a the optimize method. - /// + /// public PngChunkFilter? ChunkFilter { get; set; } + /// + public bool IgnoreMetadata { get; set; } + /// public bool MakeTransparentBlack { get; set; } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs index 3a8e528cc0..52d7fe6d0a 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs @@ -40,6 +40,11 @@ namespace SixLabors.ImageSharp.Formats.Png use16Bit = options.BitDepth == PngBitDepth.Bit16; bytesPerPixel = CalculateBytesPerPixel(options.ColorType, use16Bit); + if (options.IgnoreMetadata) + { + options.ChunkFilter = PngChunkFilter.ExcludeAll; + } + // Ensure we are not allowing impossible combinations. if (!PngConstants.ColorTypes.ContainsKey(options.ColorType.Value)) { diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs index fa15448164..0418b36c87 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs @@ -144,6 +144,58 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Fact] + public void IgnoreMetadata_WillExcludeAllAncillaryChunks() + { + // arrange + var testFile = TestFile.Create(TestImages.Png.PngWithMetadata); + using Image input = testFile.CreateRgba32Image(); + using var memStream = new MemoryStream(); + var encoder = new PngEncoder() { IgnoreMetadata = true, TextCompressionThreshold = 8 }; + var expectedChunkTypes = new Dictionary() + { + { PngChunkType.Header, false }, + { PngChunkType.Palette, false }, + { PngChunkType.Data, false }, + { PngChunkType.End, false } + }; + var excludedChunkTypes = new List() + { + PngChunkType.Gamma, + PngChunkType.Exif, + PngChunkType.Physical, + PngChunkType.Text, + PngChunkType.InternationalText, + PngChunkType.CompressedText, + }; + + // act + input.Save(memStream, encoder); + + // assert + Assert.True(excludedChunkTypes.Count > 0); + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + while (bytesSpan.Length > 0) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(0, 4)); + var chunkType = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + Assert.False(excludedChunkTypes.Contains(chunkType), $"{chunkType} chunk should have been excluded"); + if (expectedChunkTypes.ContainsKey(chunkType)) + { + expectedChunkTypes[chunkType] = true; + } + + bytesSpan = bytesSpan.Slice(4 + 4 + length + 4); + } + + // all expected chunk types should have been seen at least once. + foreach (PngChunkType chunkType in expectedChunkTypes.Keys) + { + Assert.True(expectedChunkTypes[chunkType], $"We expect {chunkType} chunk to be present at least once"); + } + } + [Theory] [InlineData(PngChunkFilter.ExcludeGammaChunk)] [InlineData(PngChunkFilter.ExcludeExifChunk)] From ec3656ff7a189acc6adf3d2f7df04aef22d5f4ef Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 1 May 2020 10:38:47 +0200 Subject: [PATCH 201/213] Add PngTransparentColorBehavior enum --- .../Formats/Png/IPngEncoderOptions.cs | 5 +++-- src/ImageSharp/Formats/Png/PngEncoder.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 15 +++++++------ .../Formats/Png/PngEncoderOptions.cs | 4 ++-- .../Png/PngTransparentColorBehavior.cs | 22 +++++++++++++++++++ .../Formats/Png/PngEncoderTests.cs | 8 +++---- 6 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 770afa3c57..ca9d5757fe 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -70,8 +70,9 @@ namespace SixLabors.ImageSharp.Formats.Png PngChunkFilter? ChunkFilter { get; } /// - /// Gets a value indicating whether fully transparent pixels should be converted to black pixels. + /// Gets a value indicating whether fully transparent pixels that may contain R, G, B values which are not 0, + /// should be converted to transparent black, which can yield in better compression in some cases. /// - bool MakeTransparentBlack { get; } + PngTransparentColorBehavior TransparentColorBehavior { get; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 062e56c1d3..d4ca4b7dfe 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Png public bool IgnoreMetadata { get; set; } /// - public bool MakeTransparentBlack { get; set; } + public PngTransparentColorBehavior TransparentColorBehavior { get; set; } /// /// Encodes the image to the specified stream from the . diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 12ffb2cfcf..05c17f376a 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -145,10 +145,11 @@ namespace SixLabors.ImageSharp.Formats.Png PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); Image clonedImage = null; - if (this.options.MakeTransparentBlack) + bool clearTransparency = this.options.TransparentColorBehavior == PngTransparentColorBehavior.Clear; + if (clearTransparency) { clonedImage = image.Clone(); - MakeTransparentPixelsBlack(clonedImage); + ClearTransparentPixels(clonedImage); } IndexedImageFrame quantized = this.CreateQuantizedImage(image, clonedImage); @@ -162,7 +163,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePhysicalChunk(stream, metadata); this.WriteExifChunk(stream, metadata); this.WriteTextChunks(stream, pngMetadata); - this.WriteDataChunks(this.options.MakeTransparentBlack ? clonedImage : image, quantized, stream); + this.WriteDataChunks(clearTransparency ? clonedImage : image, quantized, stream); this.WriteEndChunk(stream); stream.Flush(); @@ -190,11 +191,11 @@ namespace SixLabors.ImageSharp.Formats.Png } /// - /// Makes transparent pixels black. + /// Convert transparent pixels, to transparent black pixels, which can yield to better compression in some cases. /// /// The type of the pixel. /// The cloned image where the transparent pixels will be changed. - private static void MakeTransparentPixelsBlack(Image image) + private static void ClearTransparentPixels(Image image) where TPixel : unmanaged, IPixel { Rgba32 rgba32 = default; @@ -207,7 +208,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (rgba32.A == 0) { - span[x].FromRgba32(Color.Black); + span[x].FromRgba32(Color.Transparent); } } } @@ -224,7 +225,7 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : unmanaged, IPixel { IndexedImageFrame quantized; - if (this.options.MakeTransparentBlack) + if (this.options.TransparentColorBehavior == PngTransparentColorBehavior.Clear) { quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, clonedImage); this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, quantized); diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index d0eb1a843d..e46dafada5 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.InterlaceMethod = source.InterlaceMethod; this.ChunkFilter = source.ChunkFilter; this.IgnoreMetadata = source.IgnoreMetadata; - this.MakeTransparentBlack = source.MakeTransparentBlack; + this.TransparentColorBehavior = source.TransparentColorBehavior; } /// @@ -68,6 +68,6 @@ namespace SixLabors.ImageSharp.Formats.Png public bool IgnoreMetadata { get; set; } /// - public bool MakeTransparentBlack { get; set; } + public PngTransparentColorBehavior TransparentColorBehavior { get; set; } } } diff --git a/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs b/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs new file mode 100644 index 0000000000..b459751c4b --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the GNU Affero General Public License, Version 3. + +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// Enum indicating how the transparency should be handled on encoding. + /// + public enum PngTransparentColorBehavior + { + /// + /// Converts fully transparent pixels that may contain R, G, B values which are not 0, + /// to transparent black, which can yield in better compression in some cases. + /// + Clear, + + /// + /// The transparency will be kept as is. + /// + Preserve + } +} diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 857445260d..d29279b299 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -392,17 +392,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [Theory] [InlineData(PngColorType.Palette)] - [InlineData(PngColorType.Rgb)] [InlineData(PngColorType.RgbWithAlpha)] - [InlineData(PngColorType.Grayscale)] [InlineData(PngColorType.GrayscaleWithAlpha)] - public void Encode_WithMakeTransparentBlackOption_Works(PngColorType colorType) + public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType colorType) { // arrange var image = new Image(50, 50); var encoder = new PngEncoder() { - MakeTransparentBlack = true, + TransparentColorBehavior = PngTransparentColorBehavior.Clear, ColorType = colorType }; Rgba32 rgba32 = Color.Blue; @@ -442,7 +440,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png if (y > 25) { - expectedColor = Color.Black; + expectedColor = Color.Transparent; } for (int x = 0; x < actual.Width; x++) From 129b6392d5161c8686aea1cda13349fa78ee231d Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 1 May 2020 10:50:17 +0200 Subject: [PATCH 202/213] Switched Preserve to be 0 for PngTransparentColorBehavior enum --- src/ImageSharp/Formats/Png/PngChunkFilter.cs | 2 +- .../Formats/Png/PngTransparentColorBehavior.cs | 10 +++++----- .../Formats/Png/PngEncoderTests.Chunks.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngChunkFilter.cs b/src/ImageSharp/Formats/Png/PngChunkFilter.cs index 31d3012a6d..4e8b5ab96f 100644 --- a/src/ImageSharp/Formats/Png/PngChunkFilter.cs +++ b/src/ImageSharp/Formats/Png/PngChunkFilter.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; diff --git a/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs b/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs index b459751c4b..a288ecab5c 100644 --- a/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs +++ b/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs @@ -9,14 +9,14 @@ namespace SixLabors.ImageSharp.Formats.Png public enum PngTransparentColorBehavior { /// - /// Converts fully transparent pixels that may contain R, G, B values which are not 0, - /// to transparent black, which can yield in better compression in some cases. + /// The transparency will be kept as is. /// - Clear, + Preserve = 0, /// - /// The transparency will be kept as is. + /// Converts fully transparent pixels that may contain R, G, B values which are not 0, + /// to transparent black, which can yield in better compression in some cases. /// - Preserve + Clear = 1, } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs index 0418b36c87..fa63f73e06 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs @@ -1,5 +1,5 @@ // Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. +// Licensed under the GNU Affero General Public License, Version 3. using System; using System.Buffers.Binary; From b69d772659bcac29bdc4b51cb31c29415c97df63 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 1 May 2020 12:12:04 +0200 Subject: [PATCH 203/213] Rename PngTransparentColorBehavior to PngTransparentColorMode --- src/ImageSharp/Formats/Png/IPngEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoder.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 ++-- src/ImageSharp/Formats/Png/PngEncoderOptions.cs | 4 ++-- ...TransparentColorBehavior.cs => PngTransparentColorMode.cs} | 2 +- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) rename src/ImageSharp/Formats/Png/{PngTransparentColorBehavior.cs => PngTransparentColorMode.cs} (93%) diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 409a306dd3..66117371ed 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -73,6 +73,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets a value indicating whether fully transparent pixels that may contain R, G, B values which are not 0, /// should be converted to transparent black, which can yield in better compression in some cases. /// - PngTransparentColorBehavior TransparentColorBehavior { get; } + PngTransparentColorMode TransparentColorMode { get; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index a7f0356178..9b1fc80e07 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Png public bool IgnoreMetadata { get; set; } /// - public PngTransparentColorBehavior TransparentColorBehavior { get; set; } + public PngTransparentColorMode TransparentColorMode { get; set; } /// /// Encodes the image to the specified stream from the . diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index ba5dd663df..6c30550c2a 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Formats.Png PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngEncoderOptionsHelpers.AdjustOptions(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); Image clonedImage = null; - bool clearTransparency = this.options.TransparentColorBehavior == PngTransparentColorBehavior.Clear; + bool clearTransparency = this.options.TransparentColorMode == PngTransparentColorMode.Clear; if (clearTransparency) { clonedImage = image.Clone(); @@ -225,7 +225,7 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : unmanaged, IPixel { IndexedImageFrame quantized; - if (this.options.TransparentColorBehavior == PngTransparentColorBehavior.Clear) + if (this.options.TransparentColorMode == PngTransparentColorMode.Clear) { quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, clonedImage); this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, quantized); diff --git a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs index 9166106747..53e6ee30f8 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.InterlaceMethod = source.InterlaceMethod; this.ChunkFilter = source.ChunkFilter; this.IgnoreMetadata = source.IgnoreMetadata; - this.TransparentColorBehavior = source.TransparentColorBehavior; + this.TransparentColorMode = source.TransparentColorMode; } /// @@ -68,6 +68,6 @@ namespace SixLabors.ImageSharp.Formats.Png public bool IgnoreMetadata { get; set; } /// - public PngTransparentColorBehavior TransparentColorBehavior { get; set; } + public PngTransparentColorMode TransparentColorMode { get; set; } } } diff --git a/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs b/src/ImageSharp/Formats/Png/PngTransparentColorMode.cs similarity index 93% rename from src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs rename to src/ImageSharp/Formats/Png/PngTransparentColorMode.cs index a288ecab5c..63967c153f 100644 --- a/src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs +++ b/src/ImageSharp/Formats/Png/PngTransparentColorMode.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Enum indicating how the transparency should be handled on encoding. /// - public enum PngTransparentColorBehavior + public enum PngTransparentColorMode { /// /// The transparency will be kept as is. diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 419bb8c056..4f2490f9a6 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -400,7 +400,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png var image = new Image(50, 50); var encoder = new PngEncoder() { - TransparentColorBehavior = PngTransparentColorBehavior.Clear, + TransparentColorMode = PngTransparentColorMode.Clear, ColorType = colorType }; Rgba32 rgba32 = Color.Blue; From 9415e583679a776d0ffd8f7b438e2b0a1b35c48c Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 8 May 2020 16:46:31 +0200 Subject: [PATCH 204/213] Change Scanlines and SamplesPerLine from short to int --- .../Formats/Jpeg/Components/Decoder/JpegFrame.cs | 8 ++++---- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs index 7fc3f0d97a..483c22a39d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the GNU Affero General Public License, Version 3. using System; @@ -28,12 +28,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Gets or sets the number of scanlines within the frame. /// - public short Scanlines { get; set; } + public int Scanlines { get; set; } /// /// Gets or sets the number of samples per scanline. /// - public short SamplesPerLine { get; set; } + public int SamplesPerLine { get; set; } /// /// Gets or sets the number of components within a frame. In progressive frames this value can range from only 1 to 4. @@ -105,4 +105,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index a754bfd2e7..e61ca326aa 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -841,8 +841,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg Extended = frameMarker.Marker == JpegConstants.Markers.SOF1, Progressive = frameMarker.Marker == JpegConstants.Markers.SOF2, Precision = this.temp[0], - Scanlines = (short)((this.temp[1] << 8) | this.temp[2]), - SamplesPerLine = (short)((this.temp[3] << 8) | this.temp[4]), + Scanlines = (this.temp[1] << 8) | this.temp[2], + SamplesPerLine = (this.temp[3] << 8) | this.temp[4], ComponentCount = this.temp[5] }; From bd826f170329abfbc91fa9bb8074fb9dbb621099 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 9 May 2020 14:03:16 +0100 Subject: [PATCH 205/213] Ensure min dimension of 1px following rounding. Fix #1195 --- .../Transforms/Resize/ResizeHelper.cs | 19 ++++++++++++------- .../Processors/Transforms/ResizeTests.cs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs index 6066efd1cd..6fd87b3f8a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // case ResizeMode.Stretch: default: - return (new Size(width, height), new Rectangle(0, 0, width, height)); + return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(0, 0, width, height)); } } @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } // Target image width and height can be different to the rectangle width and height. - return (new Size(width, height), new Rectangle(targetX, targetY, targetWidth, targetHeight)); + return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(targetX, targetY, Sanitize(targetWidth), Sanitize(targetHeight))); } // Switch to pad mode to downscale and calculate from there. @@ -253,7 +253,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } // Target image width and height can be different to the rectangle width and height. - return (new Size(width, height), new Rectangle(targetX, targetY, targetWidth, targetHeight)); + return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(targetX, targetY, Sanitize(targetWidth), Sanitize(targetHeight))); } private static (Size, Rectangle) CalculateMaxRectangle( @@ -282,7 +282,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } // Replace the size to match the rectangle. - return (new Size(targetWidth, targetHeight), new Rectangle(0, 0, targetWidth, targetHeight)); + return (new Size(Sanitize(targetWidth), Sanitize(targetHeight)), new Rectangle(0, 0, Sanitize(targetWidth), Sanitize(targetHeight))); } private static (Size, Rectangle) CalculateMinRectangle( @@ -330,7 +330,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } // Replace the size to match the rectangle. - return (new Size(targetWidth, targetHeight), new Rectangle(0, 0, targetWidth, targetHeight)); + return (new Size(Sanitize(targetWidth), Sanitize(targetHeight)), new Rectangle(0, 0, Sanitize(targetWidth), Sanitize(targetHeight))); } private static (Size, Rectangle) CalculatePadRectangle( @@ -398,7 +398,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } // Target image width and height can be different to the rectangle width and height. - return (new Size(width, height), new Rectangle(targetX, targetY, targetWidth, targetHeight)); + return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(targetX, targetY, Sanitize(targetWidth), Sanitize(targetHeight))); } private static (Size, Rectangle) CalculateManualRectangle( @@ -419,9 +419,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int targetHeight = targetRectangle.Height > 0 ? targetRectangle.Height : height; // Target image width and height can be different to the rectangle width and height. - return (new Size(width, height), new Rectangle(targetX, targetY, targetWidth, targetHeight)); + return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(targetX, targetY, Sanitize(targetWidth), Sanitize(targetHeight))); } private static void ThrowInvalid(string message) => throw new InvalidOperationException(message); + + private static int Sanitize(int input) + { + return Math.Max(1, input); + } } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index aec0d2a1f6..5feb8e9f07 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -605,5 +605,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2)); } } + + [Fact] + public void Issue1195() + { + using (var image = new Image(2, 300)) + { + var size = new Size(50, 50); + image.Mutate(x => x + .Resize( + new ResizeOptions + { + Size = size, + Mode = ResizeMode.Max + })); + } + } } } From 0fd2a4c5f7dd4c9774007f045eb752464a9a9495 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 9 May 2020 21:03:56 +0100 Subject: [PATCH 206/213] Update ResizeHelper.cs --- .../Processors/Transforms/Resize/ResizeHelper.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs index 6fd87b3f8a..aa5c80b76b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // case ResizeMode.Stretch: default: - return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(0, 0, width, height)); + return (new Size(Sanitize(width), Sanitize(height)), new Rectangle(0, 0, Sanitize(width), Sanitize(height))); } } @@ -424,9 +424,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private static void ThrowInvalid(string message) => throw new InvalidOperationException(message); - private static int Sanitize(int input) - { - return Math.Max(1, input); - } + private static int Sanitize(int input) => Math.Max(1, input); } } From 6bd5672639f716c4977feb99014a08226582dd0c Mon Sep 17 00:00:00 2001 From: Jaben Cargman Date: Wed, 13 May 2020 01:54:34 -0400 Subject: [PATCH 207/213] Minor typo. "commmon" -> "common" --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bd9007e4f9..185d2e362c 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Please visit https://sixlabors.com/pricing for details. ## Documentation - [Detailed documentation](https://sixlabors.github.io/docs/) for the ImageSharp API is available. This includes additional conceptual documentation to help you get started. -- Our [Samples Repository](https://github.com/SixLabors/Samples/tree/master/ImageSharp) is also available containing buildable code samples demonstrating commmon activities. +- Our [Samples Repository](https://github.com/SixLabors/Samples/tree/master/ImageSharp) is also available containing buildable code samples demonstrating common activities. ## Questions @@ -95,4 +95,4 @@ Please... Spread the word, contribute algorithms, submit performance improvement - [Dirk Lemstra](https://github.com/dlemstra) - [Anton Firsov](https://github.com/antonfirsov) - [Scott Williams](https://github.com/tocsoft) -- [Brian Popow](https://github.com/brianpopow) \ No newline at end of file +- [Brian Popow](https://github.com/brianpopow) From 6bbe57c5d338c4124e6477277d7b7f0ceafbef31 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 17 May 2020 00:43:07 +0100 Subject: [PATCH 208/213] Add hardware accelerated checksums --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 14 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 13 +- src/ImageSharp/Formats/Png/Zlib/Adler32.cs | 343 ++++++++++++------ src/ImageSharp/Formats/Png/Zlib/Crc32.Lut.cs | 70 ++++ src/ImageSharp/Formats/Png/Zlib/Crc32.cs | 290 +++++++++------ src/ImageSharp/Formats/Png/Zlib/IChecksum.cs | 43 --- src/ImageSharp/Formats/Png/Zlib/README.md | 10 +- .../Formats/Png/Zlib/ZlibDeflateStream.cs | 8 +- ...on-generic-polynomials-pclmulqdq-paper.pdf | Bin 0 -> 384202 bytes tests/Directory.Build.targets | 1 + .../General/Adler32Benchmark.cs | 72 ++++ .../General/Crc32Benchmark.cs | 72 ++++ .../ImageSharp.Benchmarks.csproj | 1 + .../Formats/Png/PngDecoderTests.Chunks.cs | 57 ++- 14 files changed, 693 insertions(+), 301 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/Zlib/Crc32.Lut.cs delete mode 100644 src/ImageSharp/Formats/Png/Zlib/IChecksum.cs create mode 100644 src/ImageSharp/Formats/Png/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf create mode 100644 tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d6ba088958..b6943e5ac1 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -30,11 +30,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly byte[] buffer = new byte[4]; - /// - /// Reusable CRC for validating chunks. - /// - private readonly Crc32 crc = new Crc32(); - /// /// The global configuration. /// @@ -1159,18 +1154,17 @@ namespace SixLabors.ImageSharp.Formats.Png /// The . private void ValidateChunk(in PngChunk chunk) { - uint crc = this.ReadChunkCrc(); + uint inputCrc = this.ReadChunkCrc(); if (chunk.IsCritical) { Span chunkType = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); - this.crc.Reset(); - this.crc.Update(chunkType); - this.crc.Update(chunk.Data.GetSpan()); + uint validCrc = Crc32.Calculate(chunkType); + validCrc = Crc32.Calculate(validCrc, chunk.Data.GetSpan()); - if (this.crc.Value != crc) + if (validCrc != inputCrc) { string chunkTypeName = Encoding.ASCII.GetString(chunkType); PngThrowHelper.ThrowInvalidChunkCrc(chunkTypeName); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index c150388477..5f62dc8528 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -47,11 +47,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly byte[] chunkDataBuffer = new byte[16]; - /// - /// Reusable CRC for validating chunks. - /// - private readonly Crc32 crc = new Crc32(); - /// /// The encoder options /// @@ -1041,18 +1036,16 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(this.buffer, 0, 8); - this.crc.Reset(); - - this.crc.Update(this.buffer.AsSpan(4, 4)); // Write the type buffer + uint crc = Crc32.Calculate(this.buffer.AsSpan(4, 4)); // Write the type buffer if (data != null && length > 0) { stream.Write(data, offset, length); - this.crc.Update(data.AsSpan(offset, length)); + crc = Crc32.Calculate(crc, data.AsSpan(offset, length)); } - BinaryPrimitives.WriteUInt32BigEndian(this.buffer, (uint)this.crc.Value); + BinaryPrimitives.WriteUInt32BigEndian(this.buffer, crc); stream.Write(this.buffer, 0, 4); // write the crc } diff --git a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs index 3a5a37ce20..b8cbc8f922 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs @@ -4,145 +4,278 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif namespace SixLabors.ImageSharp.Formats.Png.Zlib { /// - /// Computes Adler32 checksum for a stream of data. An Adler32 - /// checksum is not as reliable as a CRC32 checksum, but a lot faster to - /// compute. + /// Calculates the 32 bit Adler checksum of a given buffer according to + /// RFC 1950. ZLIB Compressed Data Format Specification version 3.3) /// - /// - /// The specification for Adler32 may be found in RFC 1950. - /// ZLIB Compressed Data Format Specification version 3.3) - /// - /// - /// From that document: - /// - /// "ADLER32 (Adler-32 checksum) - /// This contains a checksum value of the uncompressed data - /// (excluding any dictionary data) computed according to Adler-32 - /// algorithm. This algorithm is a 32-bit extension and improvement - /// of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 - /// standard. - /// - /// Adler-32 is composed of two sums accumulated per byte: s1 is - /// the sum of all bytes, s2 is the sum of all s1 values. Both sums - /// are done modulo 65521. s1 is initialized to 1, s2 to zero. The - /// Adler-32 checksum is stored as s2*65536 + s1 in most- - /// significant-byte first (network) order." - /// - /// "8.2. The Adler-32 algorithm - /// - /// The Adler-32 algorithm is much faster than the CRC32 algorithm yet - /// still provides an extremely low probability of undetected errors. - /// - /// The modulo on unsigned long accumulators can be delayed for 5552 - /// bytes, so the modulo operation time is negligible. If the bytes - /// are a, b, c, the second sum is 3a + 2b + c + 3, and so is position - /// and order sensitive, unlike the first sum, which is just a - /// checksum. That 65521 is prime is important to avoid a possible - /// large class of two-byte errors that leave the check unchanged. - /// (The Fletcher checksum uses 255, which is not prime and which also - /// makes the Fletcher check insensitive to single byte changes 0 - - /// 255.) - /// - /// The sum s1 is initialized to 1 instead of zero to make the length - /// of the sequence part of s2, so that the length does not have to be - /// checked separately. (Any sequence of zeroes has a Fletcher - /// checksum of zero.)" - /// - /// - /// - internal sealed class Adler32 : IChecksum + internal static class Adler32 { - /// - /// largest prime smaller than 65536 - /// - private const uint Base = 65521; +#if SUPPORTS_RUNTIME_INTRINSICS + private const int MinBufferSize = 64; +#endif + + // Largest prime smaller than 65536 + private const uint BASE = 65521; + + // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + private const uint NMAX = 5552; /// - /// The checksum calculated to far. + /// Calculates the Adler32 checksum with the bytes taken from the span. /// - private uint checksum; + /// The readonly span of bytes. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static uint Calculate(ReadOnlySpan buffer) + => Calculate(1U, buffer); /// - /// Initializes a new instance of the class. - /// The checksum starts off with a value of 1. + /// Calculates the Adler32 checksum with the bytes taken from the span and seed. /// - public Adler32() + /// The input Adler32 value. + /// The readonly span of bytes. + /// The . + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + public static uint Calculate(uint adler, ReadOnlySpan buffer) { - this.Reset(); - } + if (buffer.IsEmpty) + { + return 1U; + } - /// - public long Value - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.checksum; - } +#if SUPPORTS_RUNTIME_INTRINSICS + if (Sse3.IsSupported && buffer.Length >= MinBufferSize) + { + return CalculateSse(adler, buffer); + } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset() - { - this.checksum = 1; + return CalculateScalar(adler, buffer); +#else + return CalculateScalar(adler, buffer); +#endif } - /// - /// Updates the checksum with a byte value. - /// - /// - /// The data value to add. The high byte of the int is ignored. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Update(int value) + // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/adler32_simd.c +#if SUPPORTS_RUNTIME_INTRINSICS + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + private static unsafe uint CalculateSse(uint adler, ReadOnlySpan buffer) { - // We could make a length 1 byte array and call update again, but I - // would rather not have that overhead - uint s1 = this.checksum & 0xFFFF; - uint s2 = this.checksum >> 16; + uint s1 = adler & 0xFFFF; + uint s2 = (adler >> 16) & 0xFFFF; + + // Process the data in blocks. + const int BLOCK_SIZE = 1 << 5; + + uint length = (uint)buffer.Length; + uint blocks = length / BLOCK_SIZE; + length -= blocks * BLOCK_SIZE; + + int index = 0; + fixed (byte* bufferPtr = &buffer[0]) + { + index += (int)blocks * BLOCK_SIZE; + var localBufferPtr = bufferPtr; + + // _mm_setr_epi8 on x86 + var tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17); + var tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + Vector128 zero = Vector128.Zero; + var ones = Vector128.Create((short)1); + + while (blocks > 0) + { + uint n = NMAX / BLOCK_SIZE; /* The NMAX constraint. */ + if (n > blocks) + { + n = blocks; + } - s1 = (s1 + ((uint)value & 0xFF)) % Base; - s2 = (s1 + s2) % Base; + blocks -= n; - this.checksum = (s2 << 16) + s1; + // Process n blocks of data. At most NMAX data bytes can be + // processed before s2 must be reduced modulo BASE. + Vector128 v_ps = Vector128.CreateScalar(s1 * n).AsInt32(); + Vector128 v_s2 = Vector128.CreateScalar(s2).AsInt32(); + Vector128 v_s1 = Vector128.Zero; + + do + { + // Load 32 input bytes. + Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr); + Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 16); + + // Add previous block byte sum to v_ps. + v_ps = Sse2.Add(v_ps, v_s1); + + // Horizontally add the bytes for s1, multiply-adds the + // bytes by [ 32, 31, 30, ... ] for s2. + v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsInt32()); + Vector128 mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1); + v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones)); + + v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsInt32()); + Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2); + v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones)); + + localBufferPtr += BLOCK_SIZE; + } + while (--n > 0); + + v_s2 = Sse2.Add(v_s2, Sse2.ShiftLeftLogical(v_ps, 5)); + + // Sum epi32 ints v_s1(s2) and accumulate in s1(s2). + const byte S2301 = 0b1011_0001; // A B C D -> B A D C + const byte S1032 = 0b0100_1110; // A B C D -> C D A B + + v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S2301)); + v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032)); + + s1 += (uint)v_s1.ToScalar(); + + v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301)); + v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032)); + + s2 = (uint)v_s2.ToScalar(); + + // Reduce. + s1 %= BASE; + s2 %= BASE; + } + } + + ref byte bufferRef = ref MemoryMarshal.GetReference(buffer); + + if (length > 0) + { + if (length >= 16) + { + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + length -= 16; + } + + while (length-- > 0) + { + s2 += s1 += Unsafe.Add(ref bufferRef, index++); + } + + if (s1 >= BASE) + { + s1 -= BASE; + } + + s2 %= BASE; + } + + return s1 | (s2 << 16); } +#endif - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Update(ReadOnlySpan data) + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + private static uint CalculateScalar(uint adler, ReadOnlySpan buffer) { - ref byte dataRef = ref MemoryMarshal.GetReference(data); - uint s1 = this.checksum & 0xFFFF; - uint s2 = this.checksum >> 16; + uint s1 = adler & 0xFFFF; + uint s2 = (adler >> 16) & 0xFFFF; + uint k; - int count = data.Length; - int offset = 0; + ref byte bufferRef = ref MemoryMarshal.GetReference(buffer); + uint length = (uint)buffer.Length; + int index = 0; - while (count > 0) + while (length > 0) { - // We can defer the modulo operation: - // s1 maximally grows from 65521 to 65521 + 255 * 3800 - // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 - int n = 3800; - if (n > count) + k = length < NMAX ? length : NMAX; + length -= k; + + while (k >= 16) { - n = count; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + k -= 16; } - count -= n; - while (--n >= 0) + if (k != 0) { - s1 += Unsafe.Add(ref dataRef, offset++); - s2 += s1; + do + { + s1 += Unsafe.Add(ref bufferRef, index++); + s2 += s1; + } + while (--k != 0); } - s1 %= Base; - s2 %= Base; + s1 %= BASE; + s2 %= BASE; } - this.checksum = (s2 << 16) | s1; + return (s2 << 16) | s1; } } } diff --git a/src/ImageSharp/Formats/Png/Zlib/Crc32.Lut.cs b/src/ImageSharp/Formats/Png/Zlib/Crc32.Lut.cs new file mode 100644 index 0000000000..77fb9f8250 --- /dev/null +++ b/src/ImageSharp/Formats/Png/Zlib/Crc32.Lut.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the GNU Affero General Public License, Version 3. + +namespace SixLabors.ImageSharp.Formats.Png.Zlib +{ + /// + /// Contains precalulated tables for scalar calculations. + /// + internal static partial class Crc32 + { + /// + /// The table of all possible eight bit values for fast scalar lookup. + /// + private static readonly uint[] CrcTable = + { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, + 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, + 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, + 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, + 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, + 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, + 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, + 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, + 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, + 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, + 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, + 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, + 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, + 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, + 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, + 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, + 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, + 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, + 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, + 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, + 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, + 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, + 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, + 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, + 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, + 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, + 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, + 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, + 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, + 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, + 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, + 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, + 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, + 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, + 0x2D02EF8D + }; + } +} diff --git a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs index bc3811b5dc..633b3b86d7 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs @@ -4,151 +4,201 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +#if SUPPORTS_RUNTIME_INTRINSICS +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif namespace SixLabors.ImageSharp.Formats.Png.Zlib { /// - /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: - /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + /// Calculates the 32 bit Cyclic Redundancy Check (CRC) checksum of a given buffer according to the + /// IEEE 802.3 specification. /// - /// - /// - /// Polynomials over GF(2) are represented in binary, one bit per coefficient, - /// with the lowest powers in the most significant bit. Then adding polynomials - /// is just exclusive-or, and multiplying a polynomial by x is a right shift by - /// one. If we call the above polynomial p, and represent a byte as the - /// polynomial q, also with the lowest power in the most significant bit (so the - /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - /// where a mod b means the remainder after dividing a by b. - /// - /// - /// This calculation is done using the shift-register method of multiplying and - /// taking the remainder. The register is initialized to zero, and for each - /// incoming bit, x^32 is added mod p to the register if the bit is a one (where - /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - /// x (which is shifting right by one and adding x^32 mod p if the bit shifted - /// out is a one). We start with the highest power (least significant bit) of - /// q and repeat for all eight bits of q. - /// - /// - /// The table is simply the CRC of all possible eight bit values. This is all - /// the information needed to generate CRC's on data a byte at a time for all - /// combinations of CRC register values and incoming bytes. - /// - /// - internal sealed class Crc32 : IChecksum + internal static partial class Crc32 { - /// - /// The cycle redundancy check seed - /// - private const uint CrcSeed = 0xFFFFFFFF; +#if SUPPORTS_RUNTIME_INTRINSICS + private const int MinBufferSize = 64; + private const int ChunksizeMask = 15; + + // Definitions of the bit-reflected domain constants k1, k2, k3, etc and + // the CRC32+Barrett polynomials given at the end of the paper. + private static ulong[] k1k2 = { 0x0154442bd4, 0x01c6e41596 }; + private static ulong[] k3k4 = { 0x01751997d0, 0x00ccaa009e }; + private static ulong[] k5k0 = { 0x0163cd6124, 0x0000000000 }; + private static ulong[] poly = { 0x01db710641, 0x01f7011641 }; +#endif /// - /// The table of all possible eight bit values for fast lookup. + /// Calculates the CRC checksum with the bytes taken from the span. /// - private static readonly uint[] CrcTable = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, - 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, - 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, - 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, - 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, - 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, - 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, - 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, - 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, - 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, - 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, - 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, - 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, - 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, - 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, - 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, - 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, - 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, - 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, - 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, - 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, - 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, - 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, - 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, - 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, - 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, - 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, - 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, - 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, - 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, - 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, - 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, - 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, - 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, - 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, - 0x2D02EF8D - }; + /// The readonly span of bytes. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static uint Calculate(ReadOnlySpan buffer) + => Calculate(0U, buffer); /// - /// The data checksum so far. + /// Calculates the CRC checksum with the bytes taken from the span and seed. /// - private uint crc; - - /// - public long Value + /// The input CRC value. + /// The readonly span of bytes. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static uint Calculate(uint crc, ReadOnlySpan buffer) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.crc; + if (buffer.IsEmpty) + { + return 0U; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => this.crc = (uint)value; +#if SUPPORTS_RUNTIME_INTRINSICS + if (Sse41.IsSupported && Pclmulqdq.IsSupported && buffer.Length >= MinBufferSize) + { + return ~CalculateSse(~crc, buffer); + } + else + { + return ~CalculateScalar(~crc, buffer); + } +#else + return ~CalculateScalar(~crc, buffer); +#endif } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset() +#if SUPPORTS_RUNTIME_INTRINSICS + // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/crc32_simd.c + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + private static unsafe uint CalculateSse(uint crc, ReadOnlySpan buffer) { - this.crc = 0; - } + int chunksize = buffer.Length & ~ChunksizeMask; + int length = chunksize; - /// - /// Updates the checksum with the given value. - /// - /// The byte is taken as the lower 8 bits of value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Update(int value) - { - this.crc ^= CrcSeed; - this.crc = CrcTable[(this.crc ^ value) & 0xFF] ^ (this.crc >> 8); - this.crc ^= CrcSeed; + fixed (byte* bufferPtr = &buffer[0]) + fixed (ulong* k1k2Ptr = &k1k2[0]) + fixed (ulong* k3k4Ptr = &k3k4[0]) + fixed (ulong* k5k0Ptr = &k5k0[0]) + fixed (ulong* polyPtr = &poly[0]) + { + byte* localBufferPtr = bufferPtr; + + // There's at least one block of 64. + Vector128 x1 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00)); + Vector128 x2 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10)); + Vector128 x3 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20)); + Vector128 x4 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30)); + Vector128 x5; + + x1 = Sse2.Xor(x1, Sse2.ConvertScalarToVector128UInt32(crc).AsUInt64()); + Vector128 x0 = Sse2.LoadVector128(k1k2Ptr); + + localBufferPtr += 64; + length -= 64; + + // Parallel fold blocks of 64, if any. + while (length >= 64) + { + x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); + Vector128 x6 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00); + Vector128 x7 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x00); + Vector128 x8 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x00); + + x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); + x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x11); + x3 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x11); + x4 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x11); + + Vector128 y5 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00)); + Vector128 y6 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10)); + Vector128 y7 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20)); + Vector128 y8 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30)); + + x1 = Sse2.Xor(x1, x5); + x2 = Sse2.Xor(x2, x6); + x3 = Sse2.Xor(x3, x7); + x4 = Sse2.Xor(x4, x8); + + x1 = Sse2.Xor(x1, y5); + x2 = Sse2.Xor(x2, y6); + x3 = Sse2.Xor(x3, y7); + x4 = Sse2.Xor(x4, y8); + + localBufferPtr += 64; + length -= 64; + } + + // Fold into 128-bits. + x0 = Sse2.LoadVector128(k3k4Ptr); + + x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); + x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); + x1 = Sse2.Xor(x1, x2); + x1 = Sse2.Xor(x1, x5); + + x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); + x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); + x1 = Sse2.Xor(x1, x3); + x1 = Sse2.Xor(x1, x5); + + x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); + x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); + x1 = Sse2.Xor(x1, x4); + x1 = Sse2.Xor(x1, x5); + + // Single fold blocks of 16, if any. + while (length >= 16) + { + x2 = Sse2.LoadVector128((ulong*)localBufferPtr); + + x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); + x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); + x1 = Sse2.Xor(x1, x2); + x1 = Sse2.Xor(x1, x5); + + localBufferPtr += 16; + length -= 16; + } + + // Fold 128 - bits to 64 - bits. + x2 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x10); + x3 = Vector128.Create(~0, 0, ~0, 0).AsUInt64(); // _mm_setr_epi32 on x86 + x1 = Sse2.ShiftRightLogical128BitLane(x1, 8); + x1 = Sse2.Xor(x1, x2); + + x0 = Sse2.LoadScalarVector128(k5k0Ptr); + + x2 = Sse2.ShiftRightLogical128BitLane(x1, 4); + x1 = Sse2.And(x1, x3); + x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); + x1 = Sse2.Xor(x1, x2); + + // Barret reduce to 32-bits. + x0 = Sse2.LoadVector128(polyPtr); + + x2 = Sse2.And(x1, x3); + x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x10); + x2 = Sse2.And(x2, x3); + x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00); + x1 = Sse2.Xor(x1, x2); + + crc = (uint)Sse41.Extract(x1.AsInt32(), 1); + return buffer.Length - chunksize == 0 ? crc : CalculateScalar(crc, buffer.Slice(chunksize)); + } } +#endif - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Update(ReadOnlySpan data) + [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] + private static uint CalculateScalar(uint crc, ReadOnlySpan buffer) { - this.crc ^= CrcSeed; - ref uint crcTableRef = ref MemoryMarshal.GetReference(CrcTable.AsSpan()); - for (int i = 0; i < data.Length; i++) + ref byte bufferRef = ref MemoryMarshal.GetReference(buffer); + + for (int i = 0; i < buffer.Length; i++) { - this.crc = Unsafe.Add(ref crcTableRef, (int)((this.crc ^ data[i]) & 0xFF)) ^ (this.crc >> 8); + crc = Unsafe.Add(ref crcTableRef, (int)((crc ^ Unsafe.Add(ref bufferRef, i)) & 0xFF)) ^ (crc >> 8); } - this.crc ^= CrcSeed; + return crc; } } } diff --git a/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs b/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs deleted file mode 100644 index 018508295c..0000000000 --- a/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the GNU Affero General Public License, Version 3. - -using System; - -namespace SixLabors.ImageSharp.Formats.Png.Zlib -{ - /// - /// Interface to compute a data checksum used by checked input/output streams. - /// A data checksum can be updated by one byte or with a byte array. After each - /// update the value of the current checksum can be returned by calling - /// Value. The complete checksum object can also be reset - /// so it can be used again with new data. - /// - internal interface IChecksum - { - /// - /// Gets the data checksum computed so far. - /// - long Value { get; } - - /// - /// Resets the data checksum as if no update was ever called. - /// - void Reset(); - - /// - /// Adds one byte to the data checksum. - /// - /// - /// The data value to add. The high byte of the integer is ignored. - /// - void Update(int value); - - /// - /// Updates the data checksum with the bytes taken from the span. - /// - /// - /// buffer an array of bytes - /// - void Update(ReadOnlySpan data); - } -} diff --git a/src/ImageSharp/Formats/Png/Zlib/README.md b/src/ImageSharp/Formats/Png/Zlib/README.md index 59f75d05f6..3875f98841 100644 --- a/src/ImageSharp/Formats/Png/Zlib/README.md +++ b/src/ImageSharp/Formats/Png/Zlib/README.md @@ -1,5 +1,11 @@ -Deflatestream implementation adapted from +DeflateStream implementation adapted from https://github.com/icsharpcode/SharpZipLib -LIcensed under MIT +Licensed under MIT + +Crc32 and Adler32 SIMD implementation adapted from + +https://github.com/chromium/chromium + +Licensed under BSD 3-Clause "New" or "Revised" License diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs index 4f757e4c92..02f5c54e7b 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Png.Zlib @@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// /// Computes the checksum for the data stream. /// - private readonly Adler32 adler32 = new Adler32(); + private uint adler = 1U; /// /// A value indicating whether this instance of the given entity has been disposed. @@ -133,10 +134,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib public override void SetLength(long value) => throw new NotSupportedException(); /// + [MethodImpl(InliningOptions.ShortMethod)] public override void Write(byte[] buffer, int offset, int count) { this.deflateStream.Write(buffer, offset, count); - this.adler32.Update(buffer.AsSpan(offset, count)); + this.adler = Adler32.Calculate(this.adler, buffer.AsSpan(offset, count)); } /// @@ -153,7 +155,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib this.deflateStream.Dispose(); // Add the crc - uint crc = (uint)this.adler32.Value; + uint crc = this.adler; this.rawStream.WriteByte((byte)((crc >> 24) & 0xFF)); this.rawStream.WriteByte((byte)((crc >> 16) & 0xFF)); this.rawStream.WriteByte((byte)((crc >> 8) & 0xFF)); diff --git a/src/ImageSharp/Formats/Png/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf b/src/ImageSharp/Formats/Png/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d0eca86b33851a18132d39983b2118e8da3ee7aa GIT binary patch literal 384202 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

{LABC35aZ+t^w!fb%kfniC0^^)fHUEz8(f& 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 Cetk@ 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

  • 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 z + diff --git a/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs b/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs new file mode 100644 index 0000000000..5a4a513251 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the GNU Affero General Public License, Version 3. + +using System; +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Formats.Png.Zlib; +using SharpAdler32 = ICSharpCode.SharpZipLib.Checksum.Adler32; + +namespace SixLabors.ImageSharp.Benchmarks.General +{ + [Config(typeof(Config.ShortClr))] + public class Adler32Benchmark + { + private byte[] data; + private readonly SharpAdler32 adler = new SharpAdler32(); + + [Params(1024, 2048, 4096)] + public int Count { get; set; } + + [GlobalSetup] + public void SetUp() + { + this.data = new byte[this.Count]; + new Random(1).NextBytes(this.data); + } + + [Benchmark(Baseline = true)] + public long SharpZipLibCalculate() + { + this.adler.Reset(); + this.adler.Update(this.data); + return this.adler.Value; + } + + [Benchmark] + public uint SixLaborsCalculate() + { + return Adler32.Calculate(this.data); + } + } + + // ########## 17/05/2020 ########## + // + // | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | + // |--------------------- |-------------- |------ |------------:|-------------:|-----------:|------:|--------:|------:|------:|------:|----------:| + // | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 847.94 ns | 180.284 ns | 9.882 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 1024 | 458.80 ns | 146.235 ns | 8.016 ns | 0.54 | 0.02 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 817.11 ns | 31.211 ns | 1.711 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 1024 | 421.48 ns | 86.149 ns | 4.722 ns | 0.52 | 0.01 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 879.38 ns | 37.804 ns | 2.072 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 1024 | 57.27 ns | 2.008 ns | 0.110 ns | 0.07 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 1,660.62 ns | 46.912 ns | 2.571 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 2048 | 938.41 ns | 3,137.008 ns | 171.950 ns | 0.57 | 0.10 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 1,616.69 ns | 172.974 ns | 9.481 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 2048 | 871.52 ns | 485.678 ns | 26.622 ns | 0.54 | 0.02 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 1,746.34 ns | 110.539 ns | 6.059 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 2048 | 96.31 ns | 24.491 ns | 1.342 ns | 0.06 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 3,102.18 ns | 484.204 ns | 26.541 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 4096 | 1,729.49 ns | 104.446 ns | 5.725 ns | 0.56 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 3,251.55 ns | 607.086 ns | 33.276 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 4096 | 1,669.22 ns | 25.194 ns | 1.381 ns | 0.51 | 0.01 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 3,514.15 ns | 719.548 ns | 39.441 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 4096 | 180.12 ns | 55.425 ns | 3.038 ns | 0.05 | 0.00 | - | - | - | - | +} diff --git a/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs b/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs new file mode 100644 index 0000000000..4bd273b30b --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the GNU Affero General Public License, Version 3. + +using System; +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Formats.Png.Zlib; +using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32; + +namespace SixLabors.ImageSharp.Benchmarks.General +{ + [Config(typeof(Config.ShortClr))] + public class Crc32Benchmark + { + private byte[] data; + private readonly SharpCrc32 crc = new SharpCrc32(); + + [Params(1024, 2048, 4096)] + public int Count { get; set; } + + [GlobalSetup] + public void SetUp() + { + this.data = new byte[this.Count]; + new Random(1).NextBytes(this.data); + } + + [Benchmark(Baseline = true)] + public long SharpZipLibCalculate() + { + this.crc.Reset(); + this.crc.Update(this.data); + return this.crc.Value; + } + + [Benchmark] + public long SixLaborsCalculate() + { + return Crc32.Calculate(this.data); + } + } + + // ########## 17/05/2020 ########## + // + // | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | + // |--------------------- |-------------- |------ |-------------:|-------------:|-------------:|------:|--------:|------:|------:|------:|----------:| + // | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 3,067.24 ns | 769.25 ns | 42.165 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 1024 | 2,546.86 ns | 1,106.36 ns | 60.643 ns | 0.83 | 0.02 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 3,377.15 ns | 3,903.41 ns | 213.959 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 1024 | 2,524.25 ns | 2,220.97 ns | 121.739 ns | 0.75 | 0.04 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 3,980.60 ns | 8,497.37 ns | 465.769 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 1024 | 78.68 ns | 69.82 ns | 3.827 ns | 0.02 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 7,934.29 ns | 42,550.13 ns | 2,332.316 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 2048 | 5,437.81 ns | 12,760.51 ns | 699.447 ns | 0.71 | 0.10 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 6,008.05 ns | 621.37 ns | 34.059 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 2048 | 4,791.50 ns | 3,894.94 ns | 213.495 ns | 0.80 | 0.04 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 5,900.06 ns | 1,344.70 ns | 73.707 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 2048 | 103.12 ns | 15.66 ns | 0.859 ns | 0.02 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 12,422.59 ns | 1,308.01 ns | 71.696 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 4096 | 10,524.63 ns | 6,267.56 ns | 343.546 ns | 0.85 | 0.03 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 11,888.00 ns | 1,059.25 ns | 58.061 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 4096 | 9,806.24 ns | 241.91 ns | 13.260 ns | 0.82 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 12,181.28 ns | 1,974.68 ns | 108.239 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 4096 | 192.39 ns | 10.27 ns | 0.563 ns | 0.02 | 0.00 | - | - | - | - | +} diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index f380d0a6a9..8c848fd049 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -25,6 +25,7 @@ + diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index afc6e05a6b..1a9dedc54e 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the GNU Affero General Public License, Version 3. +using System; using System.Buffers.Binary; using System.IO; using System.Text; @@ -16,6 +17,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { public partial class PngDecoderTests { + // Represents ASCII string of "123456789" + private readonly byte[] check = { 49, 50, 51, 52, 53, 54, 55, 56, 57 }; + // Contains the png marker, IHDR and pHYs chunks of a 1x1 pixel 32bit png 1 a single black pixel. private static readonly byte[] Raw1X1PngIhdrAndpHYs = { @@ -80,17 +84,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } [Fact] - public void CalculateCrc_Works() + public void CalculateCrc_Works_LongerRun() { - // arrange - var data = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; - var crc = new Crc32(); - - // act - crc.Update(data); + // Longer run, enough to require moving the point in SIMD implementation with + // offset for dropping back to scalar. + var data = new byte[] + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215 + }; // assert - Assert.Equal(0x88AA689F, crc.Value); + uint crc = Crc32.Calculate(data); + Assert.Equal(0xC1125402, crc); + } + + [Fact] + public void CalculateCrc_Works() + { + // Short run, less than 64. + var data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; + uint crc = Crc32.Calculate(data); + + Assert.Equal(0x88AA689F, crc); } private static string GetChunkTypeName(uint value) From c910a81d7e563c39b46c59282eeefbb168d0005c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 17 May 2020 16:29:05 +0100 Subject: [PATCH 209/213] Add default seed values --- src/ImageSharp/Formats/Png/Zlib/Adler32.cs | 9 +++++++-- src/ImageSharp/Formats/Png/Zlib/Crc32.cs | 9 +++++++-- src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs index b8cbc8f922..bd354a508f 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs @@ -17,6 +17,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib ///
  • internal static class Adler32 { + /// + /// The default initial seed value of a Adler32 checksum calculation. + /// + public const uint SeedValue = 1U; + #if SUPPORTS_RUNTIME_INTRINSICS private const int MinBufferSize = 64; #endif @@ -34,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// The . [MethodImpl(InliningOptions.ShortMethod)] public static uint Calculate(ReadOnlySpan buffer) - => Calculate(1U, buffer); + => Calculate(SeedValue, buffer); /// /// Calculates the Adler32 checksum with the bytes taken from the span and seed. @@ -47,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (buffer.IsEmpty) { - return 1U; + return SeedValue; } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs index 633b3b86d7..ad047a41d7 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs @@ -17,6 +17,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// internal static partial class Crc32 { + /// + /// The default initial seed value of a Crc32 checksum calculation. + /// + public const uint SeedValue = 0U; + #if SUPPORTS_RUNTIME_INTRINSICS private const int MinBufferSize = 64; private const int ChunksizeMask = 15; @@ -36,7 +41,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// The . [MethodImpl(InliningOptions.ShortMethod)] public static uint Calculate(ReadOnlySpan buffer) - => Calculate(0U, buffer); + => Calculate(SeedValue, buffer); /// /// Calculates the CRC checksum with the bytes taken from the span and seed. @@ -49,7 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (buffer.IsEmpty) { - return 0U; + return SeedValue; } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs index 02f5c54e7b..3257fa8846 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// /// Computes the checksum for the data stream. /// - private uint adler = 1U; + private uint adler = Adler32.SeedValue; /// /// A value indicating whether this instance of the given entity has been disposed. From f8809f5d4d4d6ce8b91478398f838424f132b7a1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 May 2020 16:20:43 +0100 Subject: [PATCH 210/213] Update Adler32.cs --- src/ImageSharp/Formats/Png/Zlib/Adler32.cs | 217 +++++++++------------ 1 file changed, 95 insertions(+), 122 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs index bd354a508f..dc8b7ad0d0 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs @@ -3,12 +3,12 @@ using System; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; #if SUPPORTS_RUNTIME_INTRINSICS using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; #endif +#pragma warning disable IDE0007 // Use implicit type namespace SixLabors.ImageSharp.Formats.Png.Zlib { /// @@ -22,16 +22,22 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// public const uint SeedValue = 1U; -#if SUPPORTS_RUNTIME_INTRINSICS - private const int MinBufferSize = 64; -#endif - // Largest prime smaller than 65536 private const uint BASE = 65521; // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 private const uint NMAX = 5552; +#if SUPPORTS_RUNTIME_INTRINSICS + private const int MinBufferSize = 64; + + private static ReadOnlySpan Tap1Tap2 => new byte[] + { + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, // tap1 + 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 // tap2 + }; +#endif + /// /// Calculates the Adler32 checksum with the bytes taken from the span. /// @@ -83,14 +89,15 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib length -= blocks * BLOCK_SIZE; int index = 0; - fixed (byte* bufferPtr = &buffer[0]) + fixed (byte* bufferPtr = buffer) + fixed (byte* tapPtr = Tap1Tap2) { index += (int)blocks * BLOCK_SIZE; var localBufferPtr = bufferPtr; // _mm_setr_epi8 on x86 - var tap1 = Vector128.Create(32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17); - var tap2 = Vector128.Create(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1); + Vector128 tap1 = Sse2.LoadVector128((sbyte*)tapPtr); + Vector128 tap2 = Sse2.LoadVector128((sbyte*)(tapPtr + 0x10)); Vector128 zero = Vector128.Zero; var ones = Vector128.Create((short)1); @@ -106,28 +113,28 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib // Process n blocks of data. At most NMAX data bytes can be // processed before s2 must be reduced modulo BASE. - Vector128 v_ps = Vector128.CreateScalar(s1 * n).AsInt32(); - Vector128 v_s2 = Vector128.CreateScalar(s2).AsInt32(); - Vector128 v_s1 = Vector128.Zero; + Vector128 v_ps = Vector128.CreateScalar(s1 * n); + Vector128 v_s2 = Vector128.CreateScalar(s2); + Vector128 v_s1 = Vector128.Zero; do { // Load 32 input bytes. Vector128 bytes1 = Sse3.LoadDquVector128(localBufferPtr); - Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 16); + Vector128 bytes2 = Sse3.LoadDquVector128(localBufferPtr + 0x10); // Add previous block byte sum to v_ps. v_ps = Sse2.Add(v_ps, v_s1); // Horizontally add the bytes for s1, multiply-adds the // bytes by [ 32, 31, 30, ... ] for s2. - v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsInt32()); + v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes1, zero).AsUInt32()); Vector128 mad1 = Ssse3.MultiplyAddAdjacent(bytes1, tap1); - v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones)); + v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad1, ones).AsUInt32()); - v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsInt32()); + v_s1 = Sse2.Add(v_s1, Sse2.SumAbsoluteDifferences(bytes2, zero).AsUInt32()); Vector128 mad2 = Ssse3.MultiplyAddAdjacent(bytes2, tap2); - v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones)); + v_s2 = Sse2.Add(v_s2, Sse2.MultiplyAddAdjacent(mad2, ones).AsUInt32()); localBufferPtr += BLOCK_SIZE; } @@ -139,148 +146,114 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib const byte S2301 = 0b1011_0001; // A B C D -> B A D C const byte S1032 = 0b0100_1110; // A B C D -> C D A B - v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S2301)); v_s1 = Sse2.Add(v_s1, Sse2.Shuffle(v_s1, S1032)); - s1 += (uint)v_s1.ToScalar(); + s1 += v_s1.ToScalar(); v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S2301)); v_s2 = Sse2.Add(v_s2, Sse2.Shuffle(v_s2, S1032)); - s2 = (uint)v_s2.ToScalar(); + s2 = v_s2.ToScalar(); // Reduce. s1 %= BASE; s2 %= BASE; } - } - - ref byte bufferRef = ref MemoryMarshal.GetReference(buffer); - if (length > 0) - { - if (length >= 16) + if (length > 0) { - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - length -= 16; - } + if (length >= 16) + { + s2 += s1 += localBufferPtr[0]; + s2 += s1 += localBufferPtr[1]; + s2 += s1 += localBufferPtr[2]; + s2 += s1 += localBufferPtr[3]; + s2 += s1 += localBufferPtr[4]; + s2 += s1 += localBufferPtr[5]; + s2 += s1 += localBufferPtr[6]; + s2 += s1 += localBufferPtr[7]; + s2 += s1 += localBufferPtr[8]; + s2 += s1 += localBufferPtr[9]; + s2 += s1 += localBufferPtr[10]; + s2 += s1 += localBufferPtr[11]; + s2 += s1 += localBufferPtr[12]; + s2 += s1 += localBufferPtr[13]; + s2 += s1 += localBufferPtr[14]; + s2 += s1 += localBufferPtr[15]; + + localBufferPtr += 16; + length -= 16; + } - while (length-- > 0) - { - s2 += s1 += Unsafe.Add(ref bufferRef, index++); - } + while (length-- > 0) + { + s2 += s1 += *localBufferPtr++; + } - if (s1 >= BASE) - { - s1 -= BASE; + if (s1 >= BASE) + { + s1 -= BASE; + } + + s2 %= BASE; } - s2 %= BASE; + return s1 | (s2 << 16); } - - return s1 | (s2 << 16); } #endif [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static uint CalculateScalar(uint adler, ReadOnlySpan buffer) + private static unsafe uint CalculateScalar(uint adler, ReadOnlySpan buffer) { uint s1 = adler & 0xFFFF; uint s2 = (adler >> 16) & 0xFFFF; uint k; - ref byte bufferRef = ref MemoryMarshal.GetReference(buffer); - uint length = (uint)buffer.Length; - int index = 0; - - while (length > 0) + fixed (byte* bufferPtr = buffer) { - k = length < NMAX ? length : NMAX; - length -= k; + var localBufferPtr = bufferPtr; + uint length = (uint)buffer.Length; - while (k >= 16) + while (length > 0) { - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; - k -= 16; - } + k = length < NMAX ? length : NMAX; + length -= k; - if (k != 0) - { - do + while (k >= 16) + { + s2 += s1 += localBufferPtr[0]; + s2 += s1 += localBufferPtr[1]; + s2 += s1 += localBufferPtr[2]; + s2 += s1 += localBufferPtr[3]; + s2 += s1 += localBufferPtr[4]; + s2 += s1 += localBufferPtr[5]; + s2 += s1 += localBufferPtr[6]; + s2 += s1 += localBufferPtr[7]; + s2 += s1 += localBufferPtr[8]; + s2 += s1 += localBufferPtr[9]; + s2 += s1 += localBufferPtr[10]; + s2 += s1 += localBufferPtr[11]; + s2 += s1 += localBufferPtr[12]; + s2 += s1 += localBufferPtr[13]; + s2 += s1 += localBufferPtr[14]; + s2 += s1 += localBufferPtr[15]; + + localBufferPtr += 16; + k -= 16; + } + + while (k-- > 0) { - s1 += Unsafe.Add(ref bufferRef, index++); - s2 += s1; + s2 += s1 += *localBufferPtr++; } - while (--k != 0); + + s1 %= BASE; + s2 %= BASE; } - s1 %= BASE; - s2 %= BASE; + return (s2 << 16) | s1; } - - return (s2 << 16) | s1; } } } From 179dc94186e879ffc9c9d3fd1da3ae7fd442496d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 May 2020 16:51:09 +0100 Subject: [PATCH 211/213] Update Crc32 based on feedback --- src/ImageSharp/Formats/Png/Zlib/Adler32.cs | 1 + src/ImageSharp/Formats/Png/Zlib/Crc32.cs | 36 +++++++----- .../General/Adler32Benchmark.cs | 56 +++++++++---------- .../General/Crc32Benchmark.cs | 56 +++++++++---------- 4 files changed, 78 insertions(+), 71 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs index dc8b7ad0d0..3d41c6b821 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs @@ -31,6 +31,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib #if SUPPORTS_RUNTIME_INTRINSICS private const int MinBufferSize = 64; + // The C# compiler emits this as a compile-time constant embedded in the PE file. private static ReadOnlySpan Tap1Tap2 => new byte[] { 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, // tap1 diff --git a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs index ad047a41d7..b25c042e19 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs @@ -12,8 +12,8 @@ using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp.Formats.Png.Zlib { /// - /// Calculates the 32 bit Cyclic Redundancy Check (CRC) checksum of a given buffer according to the - /// IEEE 802.3 specification. + /// Calculates the 32 bit Cyclic Redundancy Check (CRC) checksum of a given buffer + /// according to the IEEE 802.3 specification. /// internal static partial class Crc32 { @@ -28,10 +28,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib // Definitions of the bit-reflected domain constants k1, k2, k3, etc and // the CRC32+Barrett polynomials given at the end of the paper. - private static ulong[] k1k2 = { 0x0154442bd4, 0x01c6e41596 }; - private static ulong[] k3k4 = { 0x01751997d0, 0x00ccaa009e }; - private static ulong[] k5k0 = { 0x0163cd6124, 0x0000000000 }; - private static ulong[] poly = { 0x01db710641, 0x01f7011641 }; + private static readonly ulong[] K05Poly = + { + 0x0154442bd4, 0x01c6e41596, // k1, k2 + 0x01751997d0, 0x00ccaa009e, // k3, k4 + 0x0163cd6124, 0x0000000000, // k5, k0 + 0x01db710641, 0x01f7011641 // polynomial + }; #endif /// @@ -79,13 +82,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib int chunksize = buffer.Length & ~ChunksizeMask; int length = chunksize; - fixed (byte* bufferPtr = &buffer[0]) - fixed (ulong* k1k2Ptr = &k1k2[0]) - fixed (ulong* k3k4Ptr = &k3k4[0]) - fixed (ulong* k5k0Ptr = &k5k0[0]) - fixed (ulong* polyPtr = &poly[0]) + fixed (byte* bufferPtr = buffer) + fixed (ulong* k05PolyPtr = K05Poly) { byte* localBufferPtr = bufferPtr; + ulong* localK05PolyPtr = k05PolyPtr; // There's at least one block of 64. Vector128 x1 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00)); @@ -95,7 +96,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib Vector128 x5; x1 = Sse2.Xor(x1, Sse2.ConvertScalarToVector128UInt32(crc).AsUInt64()); - Vector128 x0 = Sse2.LoadVector128(k1k2Ptr); + + // k1, k2 + Vector128 x0 = Sse2.LoadVector128(localK05PolyPtr + 0x0); localBufferPtr += 64; length -= 64; @@ -133,7 +136,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib } // Fold into 128-bits. - x0 = Sse2.LoadVector128(k3k4Ptr); + // k3, k4 + x0 = Sse2.LoadVector128(k05PolyPtr + 0x2); x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); @@ -170,7 +174,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib x1 = Sse2.ShiftRightLogical128BitLane(x1, 8); x1 = Sse2.Xor(x1, x2); - x0 = Sse2.LoadScalarVector128(k5k0Ptr); + // k5, k0 + x0 = Sse2.LoadScalarVector128(localK05PolyPtr + 0x4); x2 = Sse2.ShiftRightLogical128BitLane(x1, 4); x1 = Sse2.And(x1, x3); @@ -178,7 +183,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib x1 = Sse2.Xor(x1, x2); // Barret reduce to 32-bits. - x0 = Sse2.LoadVector128(polyPtr); + // polynomial + x0 = Sse2.LoadVector128(localK05PolyPtr + 0x6); x2 = Sse2.And(x1, x3); x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x10); diff --git a/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs b/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs index 5a4a513251..37144bd949 100644 --- a/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs +++ b/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs @@ -41,32 +41,32 @@ namespace SixLabors.ImageSharp.Benchmarks.General // ########## 17/05/2020 ########## // - // | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | - // |--------------------- |-------------- |------ |------------:|-------------:|-----------:|------:|--------:|------:|------:|------:|----------:| - // | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 847.94 ns | 180.284 ns | 9.882 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET 4.7.2 | 1024 | 458.80 ns | 146.235 ns | 8.016 ns | 0.54 | 0.02 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 817.11 ns | 31.211 ns | 1.711 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 2.1 | 1024 | 421.48 ns | 86.149 ns | 4.722 ns | 0.52 | 0.01 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 879.38 ns | 37.804 ns | 2.072 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 3.1 | 1024 | 57.27 ns | 2.008 ns | 0.110 ns | 0.07 | 0.00 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 1,660.62 ns | 46.912 ns | 2.571 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET 4.7.2 | 2048 | 938.41 ns | 3,137.008 ns | 171.950 ns | 0.57 | 0.10 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 1,616.69 ns | 172.974 ns | 9.481 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 2.1 | 2048 | 871.52 ns | 485.678 ns | 26.622 ns | 0.54 | 0.02 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 1,746.34 ns | 110.539 ns | 6.059 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 3.1 | 2048 | 96.31 ns | 24.491 ns | 1.342 ns | 0.06 | 0.00 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 3,102.18 ns | 484.204 ns | 26.541 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET 4.7.2 | 4096 | 1,729.49 ns | 104.446 ns | 5.725 ns | 0.56 | 0.00 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 3,251.55 ns | 607.086 ns | 33.276 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 2.1 | 4096 | 1,669.22 ns | 25.194 ns | 1.381 ns | 0.51 | 0.01 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 3,514.15 ns | 719.548 ns | 39.441 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 3.1 | 4096 | 180.12 ns | 55.425 ns | 3.038 ns | 0.05 | 0.00 | - | - | - | - | + // | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | + // |--------------------- |-------------- |------ |------------:|------------:|----------:|------:|--------:|------:|------:|------:|----------:| + // | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 793.18 ns | 775.66 ns | 42.516 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 1024 | 384.86 ns | 15.64 ns | 0.857 ns | 0.49 | 0.03 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 790.31 ns | 353.34 ns | 19.368 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 1024 | 465.28 ns | 652.41 ns | 35.761 ns | 0.59 | 0.03 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 877.25 ns | 97.89 ns | 5.365 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 1024 | 45.60 ns | 13.28 ns | 0.728 ns | 0.05 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 1,537.04 ns | 428.44 ns | 23.484 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 2048 | 849.76 ns | 1,066.34 ns | 58.450 ns | 0.55 | 0.04 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 1,616.97 ns | 276.70 ns | 15.167 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 2048 | 790.77 ns | 691.71 ns | 37.915 ns | 0.49 | 0.03 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 1,735.11 ns | 1,374.22 ns | 75.325 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 2048 | 87.80 ns | 56.84 ns | 3.116 ns | 0.05 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 3,054.53 ns | 796.41 ns | 43.654 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 4096 | 1,538.90 ns | 487.02 ns | 26.695 ns | 0.50 | 0.01 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 3,223.48 ns | 32.32 ns | 1.771 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 4096 | 1,547.60 ns | 309.72 ns | 16.977 ns | 0.48 | 0.01 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 3,672.33 ns | 1,095.81 ns | 60.065 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 4096 | 159.44 ns | 36.31 ns | 1.990 ns | 0.04 | 0.00 | - | - | - | - | } diff --git a/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs b/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs index 4bd273b30b..7f85d5aad1 100644 --- a/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs +++ b/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs @@ -41,32 +41,32 @@ namespace SixLabors.ImageSharp.Benchmarks.General // ########## 17/05/2020 ########## // - // | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | - // |--------------------- |-------------- |------ |-------------:|-------------:|-------------:|------:|--------:|------:|------:|------:|----------:| - // | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 3,067.24 ns | 769.25 ns | 42.165 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET 4.7.2 | 1024 | 2,546.86 ns | 1,106.36 ns | 60.643 ns | 0.83 | 0.02 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 3,377.15 ns | 3,903.41 ns | 213.959 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 2.1 | 1024 | 2,524.25 ns | 2,220.97 ns | 121.739 ns | 0.75 | 0.04 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 3,980.60 ns | 8,497.37 ns | 465.769 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 3.1 | 1024 | 78.68 ns | 69.82 ns | 3.827 ns | 0.02 | 0.00 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 7,934.29 ns | 42,550.13 ns | 2,332.316 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET 4.7.2 | 2048 | 5,437.81 ns | 12,760.51 ns | 699.447 ns | 0.71 | 0.10 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 6,008.05 ns | 621.37 ns | 34.059 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 2.1 | 2048 | 4,791.50 ns | 3,894.94 ns | 213.495 ns | 0.80 | 0.04 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 5,900.06 ns | 1,344.70 ns | 73.707 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 3.1 | 2048 | 103.12 ns | 15.66 ns | 0.859 ns | 0.02 | 0.00 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 12,422.59 ns | 1,308.01 ns | 71.696 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET 4.7.2 | 4096 | 10,524.63 ns | 6,267.56 ns | 343.546 ns | 0.85 | 0.03 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 11,888.00 ns | 1,059.25 ns | 58.061 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 2.1 | 4096 | 9,806.24 ns | 241.91 ns | 13.260 ns | 0.82 | 0.00 | - | - | - | - | - // | | | | | | | | | | | | | - // | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 12,181.28 ns | 1,974.68 ns | 108.239 ns | 1.00 | 0.00 | - | - | - | - | - // | SixLaborsCalculate | .NET Core 3.1 | 4096 | 192.39 ns | 10.27 ns | 0.563 ns | 0.02 | 0.00 | - | - | - | - | + // | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | + // |--------------------- |-------------- |------ |-------------:|-------------:|-----------:|------:|--------:|------:|------:|------:|----------:| + // | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 2,797.77 ns | 278.697 ns | 15.276 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 1024 | 2,275.56 ns | 216.100 ns | 11.845 ns | 0.81 | 0.01 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 2,923.43 ns | 2,656.882 ns | 145.633 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 1024 | 2,257.79 ns | 75.081 ns | 4.115 ns | 0.77 | 0.04 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 2,764.14 ns | 86.281 ns | 4.729 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 1024 | 49.32 ns | 1.813 ns | 0.099 ns | 0.02 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 5,603.71 ns | 427.240 ns | 23.418 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 2048 | 4,525.02 ns | 33.931 ns | 1.860 ns | 0.81 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 5,563.32 ns | 49.337 ns | 2.704 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 2048 | 4,519.61 ns | 29.837 ns | 1.635 ns | 0.81 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 5,543.37 ns | 518.551 ns | 28.424 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 2048 | 89.07 ns | 3.312 ns | 0.182 ns | 0.02 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 11,396.95 ns | 373.450 ns | 20.470 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET 4.7.2 | 4096 | 9,070.35 ns | 271.083 ns | 14.859 ns | 0.80 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 11,127.81 ns | 239.177 ns | 13.110 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 2.1 | 4096 | 9,050.46 ns | 230.916 ns | 12.657 ns | 0.81 | 0.00 | - | - | - | - | + // | | | | | | | | | | | | | + // | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 11,098.62 ns | 687.978 ns | 37.710 ns | 1.00 | 0.00 | - | - | - | - | + // | SixLaborsCalculate | .NET Core 3.1 | 4096 | 168.11 ns | 3.633 ns | 0.199 ns | 0.02 | 0.00 | - | - | - | - | } From f6f6b51550f5fc8695e19fee39f96d0789314b06 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 18 May 2020 17:25:17 +0100 Subject: [PATCH 212/213] Better checksum tests --- .../Formats/Png/Adler32Tests.cs | 41 +++++++++++++++ .../Formats/Png/Crc32Tests.cs | 41 +++++++++++++++ .../Formats/Png/PngDecoderTests.Chunks.cs | 51 ------------------- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 1 + 4 files changed, 83 insertions(+), 51 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs diff --git a/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs b/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs new file mode 100644 index 0000000000..a0d4030c3f --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs @@ -0,0 +1,41 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the GNU Affero General Public License, Version 3. + +using System; +using SixLabors.ImageSharp.Formats.Png.Zlib; +using Xunit; +using SharpAdler32 = ICSharpCode.SharpZipLib.Checksum.Adler32; + +namespace SixLabors.ImageSharp.Tests.Formats.Png +{ + public class Adler32Tests + { + [Theory] + [InlineData(0)] + [InlineData(8)] + [InlineData(215)] + [InlineData(1024)] + [InlineData(1024 + 15)] + [InlineData(2034)] + [InlineData(4096)] + public void MatchesReference(int length) + { + var data = GetBuffer(length); + var adler = new SharpAdler32(); + adler.Update(data); + + long expected = adler.Value; + long actual = Adler32.Calculate(data); + + Assert.Equal(expected, actual); + } + + private static byte[] GetBuffer(int length) + { + var data = new byte[length]; + new Random(1).NextBytes(data); + + return data; + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs b/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs new file mode 100644 index 0000000000..b40e210e3e --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs @@ -0,0 +1,41 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the GNU Affero General Public License, Version 3. + +using System; +using SixLabors.ImageSharp.Formats.Png.Zlib; +using Xunit; +using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32; + +namespace SixLabors.ImageSharp.Tests.Formats.Png +{ + public class Crc32Tests + { + [Theory] + [InlineData(0)] + [InlineData(8)] + [InlineData(215)] + [InlineData(1024)] + [InlineData(1024 + 15)] + [InlineData(2034)] + [InlineData(4096)] + public void MatchesReference(int length) + { + var data = GetBuffer(length); + var crc = new SharpCrc32(); + crc.Update(data); + + long expected = crc.Value; + long actual = Crc32.Calculate(data); + + Assert.Equal(expected, actual); + } + + private static byte[] GetBuffer(int length) + { + var data = new byte[length]; + new Random(1).NextBytes(data); + + return data; + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index 1a9dedc54e..52393a7f1c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -83,57 +83,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } - [Fact] - public void CalculateCrc_Works_LongerRun() - { - // Longer run, enough to require moving the point in SIMD implementation with - // offset for dropping back to scalar. - var data = new byte[] - { - 0, 1, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215 - }; - - // assert - uint crc = Crc32.Calculate(data); - Assert.Equal(0xC1125402, crc); - } - - [Fact] - public void CalculateCrc_Works() - { - // Short run, less than 64. - var data = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; - uint crc = Crc32.Calculate(data); - - Assert.Equal(0x88AA689F, crc); - } - private static string GetChunkTypeName(uint value) { var data = new byte[4]; diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index fdb280ca99..98f8e95745 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -21,6 +21,7 @@ + From 8a5072b3175ba00082886dff11311f45a56b426c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 May 2020 00:48:08 +0100 Subject: [PATCH 213/213] Return input value on empty --- src/ImageSharp/Formats/Png/Zlib/Adler32.cs | 2 +- src/ImageSharp/Formats/Png/Zlib/Crc32.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs | 9 +++++++++ tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs | 9 +++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs index 3d41c6b821..d348e7df13 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Adler32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (buffer.IsEmpty) { - return SeedValue; + return adler; } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs index b25c042e19..5b29e35908 100644 --- a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs +++ b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (buffer.IsEmpty) { - return SeedValue; + return crc; } #if SUPPORTS_RUNTIME_INTRINSICS diff --git a/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs b/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs index a0d4030c3f..9c5f0f6a99 100644 --- a/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/Adler32Tests.cs @@ -10,6 +10,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { public class Adler32Tests { + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + public void ReturnsCorrectWhenEmpty(uint input) + { + Assert.Equal(input, Adler32.Calculate(input, default)); + } + [Theory] [InlineData(0)] [InlineData(8)] diff --git a/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs b/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs index b40e210e3e..56743c3ae6 100644 --- a/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs @@ -10,6 +10,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { public class Crc32Tests { + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + public void ReturnsCorrectWhenEmpty(uint input) + { + Assert.Equal(input, Crc32.Calculate(input, default)); + } + [Theory] [InlineData(0)] [InlineData(8)]

    vamva0zCD&$2Xf(& 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 literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/grayscale_a_rle_UL.tga b/tests/Images/Input/Tga/grayscale_a_rle_UL.tga new file mode 100644 index 0000000000000000000000000000000000000000..affa4090d240c2bc0e9be0acb9de205d38257f22 GIT binary patch literal 54295 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 ONB=tg=CA*C=>Gv>cGiLb literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/grayscale_a_rle_UR.tga b/tests/Images/Input/Tga/grayscale_a_rle_UR.tga new file mode 100644 index 0000000000000000000000000000000000000000..32461ab8e18ba8507a96a191eab1dacf59442039 GIT binary patch literal 54052 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 Y%io&*jp_IP{eS)TSEk?d<-c(LKim2vg8%>k literal 0 HcmV?d00001 From b164883a41c70bd3bdf919b7fc90a3095a8c236f Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 29 Mar 2020 13:24:00 +0200 Subject: [PATCH 081/213] Add additional tests for images which have bottom right and top right origin --- .../Formats/Tga/TgaDecoderTests.cs | 144 ++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 12 ++ tests/Images/Input/Tga/indexed_a_LL.tga | Bin 0 -> 66604 bytes tests/Images/Input/Tga/indexed_a_LR.tga | Bin 0 -> 66604 bytes tests/Images/Input/Tga/indexed_a_UL.tga | Bin 0 -> 66604 bytes tests/Images/Input/Tga/indexed_a_UR.tga | Bin 0 -> 66604 bytes tests/Images/Input/Tga/rgb_LR.tga | Bin 0 -> 196652 bytes tests/Images/Input/Tga/rgb_UR.tga | Bin 0 -> 196652 bytes tests/Images/Input/Tga/rgb_a_LR.tga | Bin 0 -> 262188 bytes tests/Images/Input/Tga/rgb_a_UR.tga | Bin 0 -> 262188 bytes tests/Images/Input/Tga/rgb_a_rle_LR.tga | Bin 0 -> 98317 bytes tests/Images/Input/Tga/rgb_a_rle_UR.tga | Bin 0 -> 97990 bytes tests/Images/Input/Tga/rgb_rle_LR.tga | Bin 0 -> 73337 bytes tests/Images/Input/Tga/rgb_rle_UR.tga | Bin 0 -> 73086 bytes 14 files changed, 156 insertions(+) create mode 100644 tests/Images/Input/Tga/indexed_a_LL.tga create mode 100644 tests/Images/Input/Tga/indexed_a_LR.tga create mode 100644 tests/Images/Input/Tga/indexed_a_UL.tga create mode 100644 tests/Images/Input/Tga/indexed_a_UR.tga create mode 100644 tests/Images/Input/Tga/rgb_LR.tga create mode 100644 tests/Images/Input/Tga/rgb_UR.tga create mode 100644 tests/Images/Input/Tga/rgb_a_LR.tga create mode 100644 tests/Images/Input/Tga/rgb_a_UR.tga create mode 100644 tests/Images/Input/Tga/rgb_a_rle_LR.tga create mode 100644 tests/Images/Input/Tga/rgb_a_rle_UR.tga create mode 100644 tests/Images/Input/Tga/rgb_rle_LR.tga create mode 100644 tests/Images/Input/Tga/rgb_rle_UR.tga diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index 2ce6eb3c2b..5bfb38b742 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -187,6 +187,30 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit24TopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Uncompressed_WithTopRightOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit24BottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Uncompressed_WithBottomRightOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit24RleTopLeft, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopLeftOrigin_24Bit(TestImageProvider provider) @@ -199,6 +223,30 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit24RleTopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopRightOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit24RleBottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomRightOrigin_24Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit24TopLeft, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_Palette_WithTopLeftOrigin_24Bit(TestImageProvider provider) @@ -223,6 +271,30 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit32BottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Uncompressed_WithBottomRightOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit32TopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Uncompressed_WithTopRightOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit16Rle, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_RunLengthEncoded_16Bit(TestImageProvider provider) @@ -259,6 +331,30 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit32RleTopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopRightOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit32RleBottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_RunLengthEncoded_WithBottomRightOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit16Pal, PixelTypes.Rgba32)] public void TgaDecoder_CanDecode_WithPalette_16Bit(TestImageProvider provider) @@ -283,6 +379,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Tga } } + [Theory] + [WithFile(Bit32Pal, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WithPalette_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit32PalBottomLeft, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WithPalette_WithBottomLeftOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit32PalBottomRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WithPalette_WithBottomRightOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + + [Theory] + [WithFile(Bit32PalTopRight, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_WithPalette_WithTopRightOrigin_32Bit(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder)) + { + image.DebugSave(provider); + TgaTestUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(NoAlphaBits16Bit, PixelTypes.Rgba32)] [WithFile(NoAlphaBits16BitRle, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 0622222cf9..197210f67a 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -380,9 +380,21 @@ namespace SixLabors.ImageSharp.Tests public const string Bit16 = "Tga/targa_16bit.tga"; public const string Bit16PalRle = "Tga/ccm8.tga"; public const string Bit24 = "Tga/targa_24bit.tga"; + public const string Bit24TopRight = "Tga/rgb_UR.tga"; + public const string Bit24BottomRight = "Tga/rgb_LR.tga"; public const string Bit24TopLeft = "Tga/targa_24bit_pal_origin_topleft.tga"; public const string Bit24RleTopLeft = "Tga/targa_24bit_rle_origin_topleft.tga"; + public const string Bit24RleTopRight = "Tga/rgb_rle_UR.tga"; + public const string Bit24RleBottomRight = "Tga/rgb_rle_LR.tga"; public const string Bit32 = "Tga/targa_32bit.tga"; + public const string Bit32Pal = "Tga/indexed_a_UL.tga"; + public const string Bit32PalBottomLeft = "Tga/indexed_a_LL.tga"; + public const string Bit32PalBottomRight = "Tga/indexed_a_LR.tga"; + public const string Bit32PalTopRight = "Tga/indexed_a_UR.tga"; + public const string Bit32TopRight = "Tga/rgb_a_UR.tga"; + public const string Bit32BottomRight = "Tga/rgb_a_LR.tga"; + public const string Bit32RleTopRight = "Tga/rgb_a_rle_UR.tga"; + public const string Bit32RleBottomRight = "Tga/rgb_a_rle_LR.tga"; public const string Gray8Bit = "Tga/targa_8bit.tga"; public const string Gray8BitRle = "Tga/targa_8bit_rle.tga"; public const string Gray16Bit = "Tga/grayscale_a_UL.tga"; diff --git a/tests/Images/Input/Tga/indexed_a_LL.tga b/tests/Images/Input/Tga/indexed_a_LL.tga new file mode 100644 index 0000000000000000000000000000000000000000..fbf4e8bbeca971c11a0cd56dae7a61732a97abc3 GIT binary patch literal 66604 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 G^8W!;T3X!z literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/indexed_a_LR.tga b/tests/Images/Input/Tga/indexed_a_LR.tga new file mode 100644 index 0000000000000000000000000000000000000000..09727b5d9d38faddc31462cb9748f12ff7438f46 GIT binary patch literal 66604 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%0DGa*1nGcTlY*6;xaGky{89+1IS#9ii_^MC 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 literal 0 HcmV?d00001 diff --git a/tests/Images/Input/Tga/rgb_a_LR.tga b/tests/Images/Input/Tga/rgb_a_LR.tga new file mode 100644 index 0000000000000000000000000000000000000000..210e58f0f20a803a9e937e466464dc09d7d7ca25 GIT binary patch literal 262188 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