From 78d43506d4db5447dbf8da6a322b3c272116454c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 29 Oct 2015 00:13:54 +1100 Subject: [PATCH 01/15] Cleanup plus perf Former-commit-id: eee5a95a9773ca04ae1ac4fc3621a3cede95d72b Former-commit-id: 1c6d20e0334e12c809773a43ff81326f4a4823aa Former-commit-id: bdfcd5892564543a1f65b45d57777404cdd930df --- src/ImageProcessor/ApiPortabilityAnalysis.htm | 218 ++++++++++++++++ src/ImageProcessor/Colors/Bgra.cs | 19 ++ src/ImageProcessor/Colors/ColorVector.cs | 132 ++++++++++ .../Common/Extensions/EnumerableExtensions.cs | 88 +++++++ src/ImageProcessor/Filters/Alpha.cs | 26 +- .../Filters/ColorMatrix/ColorMatrixFilter.cs | 43 ++-- src/ImageProcessor/Filters/Contrast.cs | 66 ++--- src/ImageProcessor/Filters/Invert.cs | 29 ++- .../Formats/Bmp/BmpDecoderCore.cs | 46 ++-- src/ImageProcessor/Formats/Bmp/BmpEncoder.cs | 1 + src/ImageProcessor/Formats/Jpg/JpegDecoder.cs | 66 ++--- src/ImageProcessor/Formats/Jpg/JpegEncoder.cs | 36 +-- .../Formats/Png/Zlib/InflaterInputBuffer.cs | 66 +---- .../Formats/Png/Zlib/InflaterInputStream.cs | 10 - .../Formats/Png/Zlib/ZipConstants.cs | 69 +----- src/ImageProcessor/ImageProcessor.csproj | 2 + src/ImageProcessor/Samplers/Resize - Copy.cs | 232 ++++++++++++++++++ src/ImageProcessor/Samplers/Resize.cs | 132 +++++----- .../ImageProcessor.Tests.csproj | 8 +- .../Processors/ProcessorTestBase.cs | 16 +- .../Processors/Samplers/SamplerTests.cs | 1 + tests/ImageProcessor.Tests/packages.config | 5 + 22 files changed, 967 insertions(+), 344 deletions(-) create mode 100644 src/ImageProcessor/ApiPortabilityAnalysis.htm create mode 100644 src/ImageProcessor/Colors/ColorVector.cs create mode 100644 src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs create mode 100644 src/ImageProcessor/Samplers/Resize - Copy.cs diff --git a/src/ImageProcessor/ApiPortabilityAnalysis.htm b/src/ImageProcessor/ApiPortabilityAnalysis.htm new file mode 100644 index 000000000..36a7dc2de --- /dev/null +++ b/src/ImageProcessor/ApiPortabilityAnalysis.htm @@ -0,0 +1,218 @@ + + + + .NET Portability Report + + +

+ .NET Portability Report +

+

+ Summary +

+ + + + + + + + +
Assembly.NET Core 5.0.NET Framework 4.6.1.NET Native 1.0ASP.NET 5 1.0Mono 3.3.0.0Windows 8.1Windows Phone 8.1
ImageProcessor100%99.7%100%100%97.6%97.9%97.9%
+
+

+ ImageProcessor +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Target type.NET Core 5.0.NET Framework 4.6.1.NET Native 1.0ASP.NET 5 1.0Mono 3.3.0.0Windows 8.1Windows Phone 8.1Recommended changes
System.Reflection.TypeInfo
get_Assembly
         
System.Numerics.Vector4
X
Z
Y
W
#ctor(System.Single,System.Single,System.Single,System.Single)
         
System.Array
Empty``1
         
Back to summary +
\ No newline at end of file diff --git a/src/ImageProcessor/Colors/Bgra.cs b/src/ImageProcessor/Colors/Bgra.cs index 052a036e4..861e75c0b 100644 --- a/src/ImageProcessor/Colors/Bgra.cs +++ b/src/ImageProcessor/Colors/Bgra.cs @@ -12,6 +12,10 @@ namespace ImageProcessor /// /// Represents an BGRA (blue, green, red, alpha) color. /// + /// + /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, + /// as it avoids the need to create new values for modification operations. + /// [StructLayout(LayoutKind.Explicit)] public struct Bgra : IEquatable { @@ -178,6 +182,21 @@ namespace ImageProcessor [EditorBrowsable(EditorBrowsableState.Never)] public bool IsEmpty => this.B == 0 && this.G == 0 && this.R == 0 && this.A == 0; + /// + /// Allows the implicit conversion of an instance of to a + /// . + /// + /// + /// The instance of to convert. + /// + /// + /// An instance of . + /// + public static implicit operator Bgra(ColorVector color) + { + return new Bgra((255 * color.B).ToByte(), (255 * color.G).ToByte(), (255 * color.R).ToByte(), (255 * color.A).ToByte()); + } + /// /// Allows the implicit conversion of an instance of to a /// . diff --git a/src/ImageProcessor/Colors/ColorVector.cs b/src/ImageProcessor/Colors/ColorVector.cs new file mode 100644 index 000000000..6e253f2d6 --- /dev/null +++ b/src/ImageProcessor/Colors/ColorVector.cs @@ -0,0 +1,132 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor +{ + using System.Numerics; + + public struct ColorVector + { + /// + /// The backing vector for SIMD support. + /// + private Vector4 backingVector; + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The blue component of this . + /// + /// + /// The green component of this . + /// + /// + /// The red component of this . + /// + /// + /// The alpha component of this . + /// + public ColorVector(double b, double g, double r, double a) + : this((float)b, (float)g, (float)r, (float)a) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The blue component of this . + /// + /// + /// The green component of this . + /// + /// + /// The red component of this . + /// + /// + /// The alpha component of this . + /// + public ColorVector(float b, float g, float r, float a) + : this() + { + this.backingVector.X = b; + this.backingVector.Y = g; + this.backingVector.Z = r; + this.backingVector.W = a; + } + + /// The color's blue component, between 0.0 and 1.0 + public float B + { + get + { + return this.backingVector.X; + } + + set + { + this.backingVector.X = value; + } + } + + /// The color's green component, between 0.0 and 1.0 + public float G + { + get + { + return this.backingVector.Y; + } + + set + { + this.backingVector.Y = value; + } + } + + /// The color's red component, between 0.0 and 1.0 + public float R + { + get + { + return this.backingVector.Z; + } + + set + { + this.backingVector.Z = value; + } + } + + /// The color's alpha component, between 0.0 and 1.0 + public float A + { + get + { + return this.backingVector.W; + } + + set + { + this.backingVector.W = value; + } + } + + /// + /// Allows the implicit conversion of an instance of to a + /// . + /// + /// + /// The instance of to convert. + /// + /// + /// An instance of . + /// + public static implicit operator ColorVector(Bgra color) + { + return new ColorVector(color.B / 255f, color.G / 255f, color.R / 255f, color.A / 255f); + } + } +} diff --git a/src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs b/src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs new file mode 100644 index 000000000..c492bcf8e --- /dev/null +++ b/src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs @@ -0,0 +1,88 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor +{ + using System; + using System.Collections.Generic; + + /// + /// Encapsulates a series of time saving extension methods to the interface. + /// + public static class EnumerableExtensions + { + /// + /// Generates a sequence of integral numbers within a specified range. + /// + /// + /// The start index, inclusive. + /// + /// + /// The end index, exclusive. + /// + /// + /// The incremental step. + /// + /// + /// The that contains a range of sequential integral numbers. + /// + public static IEnumerable SteppedRange(int fromInclusive, int toExclusive, int step) + { + // Borrowed from Enumerable.Range + long num = (fromInclusive + toExclusive) - 1L; + if ((toExclusive < 0) || (num > 0x7fffffffL)) + { + throw new ArgumentOutOfRangeException(nameof(toExclusive)); + } + + return RangeIterator(fromInclusive, i => i < toExclusive, step); + } + + /// + /// Generates a sequence of integral numbers within a specified range. + /// + /// + /// The start index, inclusive. + /// + /// + /// A method that has one parameter and returns a calculating the end index + /// + /// + /// The incremental step. + /// + /// + /// The that contains a range of sequential integral numbers. + /// + public static IEnumerable SteppedRange(int fromInclusive, Func toDelegate, int step) + { + return RangeIterator(fromInclusive, toDelegate, step); + } + + /// + /// Generates a sequence of integral numbers within a specified range. + /// + /// + /// The start index, inclusive. + /// + /// + /// A method that has one parameter and returns a calculating the end index + /// + /// + /// The incremental step. + /// + /// + /// The that contains a range of sequential integral numbers. + /// + private static IEnumerable RangeIterator(int fromInclusive, Func toDelegate, int step) + { + int i = fromInclusive; + while (toDelegate(i)) + { + yield return i; + i += step; + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Filters/Alpha.cs b/src/ImageProcessor/Filters/Alpha.cs index 93c335550..2f410525a 100644 --- a/src/ImageProcessor/Filters/Alpha.cs +++ b/src/ImageProcessor/Filters/Alpha.cs @@ -6,6 +6,7 @@ namespace ImageProcessor.Filters { using System; + using System.Threading.Tasks; /// /// An to change the Alpha of an . @@ -39,18 +40,21 @@ namespace ImageProcessor.Filters int startX = sourceRectangle.X; int endX = sourceRectangle.Right; - for (int y = startY; y < endY; y++) - { - if (y >= sourceY && y < sourceBottom) - { - for (int x = startX; x < endX; x++) + Parallel.For( + startY, + endY, + y => { - Bgra color = source[x, y]; - double a = color.A * alpha; - target[x, y] = new Bgra(color.B, color.G, color.R, a.ToByte()); - } - } - } + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + Bgra color = source[x, y]; + double a = color.A * alpha; + target[x, y] = new Bgra(color.B, color.G, color.R, a.ToByte()); + } + } + }); } } } diff --git a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs index 3f7eb7591..7f42669bd 100644 --- a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs +++ b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs @@ -5,6 +5,8 @@ namespace ImageProcessor.Filters { + using System.Threading.Tasks; + /// /// The color matrix filter. /// @@ -42,29 +44,32 @@ namespace ImageProcessor.Filters Bgra previousColor = source[0, 0]; Bgra pixelValue = this.ApplyMatrix(previousColor, matrix); - for (int y = startY; y < endY; y++) - { - if (y >= sourceY && y < sourceBottom) - { - for (int x = startX; x < endX; x++) + Parallel.For( + startY, + endY, + y => { - Bgra sourceColor = source[x, y]; - - // Check if this is the same as the last pixel. If so use that value - // rather than calculating it again. This is an inexpensive optimization. - if (sourceColor != previousColor) + if (y >= sourceY && y < sourceBottom) { - // Perform the operation on the pixel. - pixelValue = this.ApplyMatrix(sourceColor, matrix); + for (int x = startX; x < endX; x++) + { + Bgra sourceColor = source[x, y]; - // And setup the previous pointer - previousColor = sourceColor; - } + // Check if this is the same as the last pixel. If so use that value + // rather than calculating it again. This is an inexpensive optimization. + if (sourceColor != previousColor) + { + // Perform the operation on the pixel. + pixelValue = this.ApplyMatrix(sourceColor, matrix); - target[x, y] = pixelValue; - } - } - } + // And setup the previous pointer + previousColor = sourceColor; + } + + target[x, y] = pixelValue; + } + } + }); } /// diff --git a/src/ImageProcessor/Filters/Contrast.cs b/src/ImageProcessor/Filters/Contrast.cs index 556b3828f..c5abb79f6 100644 --- a/src/ImageProcessor/Filters/Contrast.cs +++ b/src/ImageProcessor/Filters/Contrast.cs @@ -6,6 +6,7 @@ namespace ImageProcessor.Filters { using System; + using System.Threading.Tasks; /// /// An to change the contrast of an . @@ -39,42 +40,45 @@ namespace ImageProcessor.Filters int startX = sourceRectangle.X; int endX = sourceRectangle.Right; - for (int y = startY; y < endY; y++) - { - if (y >= sourceY && y < sourceBottom) - { - for (int x = startX; x < endX; x++) + Parallel.For( + startY, + endY, + y => { - Bgra sourceColor = source[x, y]; - sourceColor = PixelOperations.ToLinear(sourceColor); + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + Bgra sourceColor = source[x, y]; + sourceColor = PixelOperations.ToLinear(sourceColor); - double r = sourceColor.R / 255.0; - r -= 0.5; - r *= contrast; - r += 0.5; - r *= 255; - r = r.ToByte(); + double r = sourceColor.R / 255.0; + r -= 0.5; + r *= contrast; + r += 0.5; + r *= 255; + r = r.ToByte(); - double g = sourceColor.G / 255.0; - g -= 0.5; - g *= contrast; - g += 0.5; - g *= 255; - g = g.ToByte(); + double g = sourceColor.G / 255.0; + g -= 0.5; + g *= contrast; + g += 0.5; + g *= 255; + g = g.ToByte(); - double b = sourceColor.B / 255.0; - b -= 0.5; - b *= contrast; - b += 0.5; - b *= 255; - b = b.ToByte(); + double b = sourceColor.B / 255.0; + b -= 0.5; + b *= contrast; + b += 0.5; + b *= 255; + b = b.ToByte(); - Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), sourceColor.A); - destinationColor = PixelOperations.ToSrgb(destinationColor); - target[x, y] = destinationColor; - } - } - } + Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), sourceColor.A); + destinationColor = PixelOperations.ToSrgb(destinationColor); + target[x, y] = destinationColor; + } + } + }); } } } diff --git a/src/ImageProcessor/Filters/Invert.cs b/src/ImageProcessor/Filters/Invert.cs index d24979a2d..241835fd1 100644 --- a/src/ImageProcessor/Filters/Invert.cs +++ b/src/ImageProcessor/Filters/Invert.cs @@ -5,6 +5,8 @@ namespace ImageProcessor.Filters { + using System.Threading.Tasks; + /// /// An to invert the colors of an . /// @@ -18,19 +20,22 @@ namespace ImageProcessor.Filters int startX = sourceRectangle.X; int endX = sourceRectangle.Right; - for (int y = startY; y < endY; y++) - { - if (y >= sourceY && y < sourceBottom) - { - for (int x = startX; x < endX; x++) + Parallel.For( + startY, + endY, + y => { - // TODO: This doesn't work for gamma test images. - Bgra color = source[x, y]; - Bgra targetColor = new Bgra((255 - color.B).ToByte(), (255 - color.G).ToByte(), (255 - color.R).ToByte(), color.A); - target[x, y] = targetColor; - } - } - } + if (y >= sourceY && y < sourceBottom) + { + for (int x = startX; x < endX; x++) + { + // TODO: This doesn't work for gamma test images. + Bgra color = source[x, y]; + Bgra targetColor = new Bgra((255 - color.B).ToByte(), (255 - color.G).ToByte(), (255 - color.R).ToByte(), color.A); + target[x, y] = targetColor; + } + } + }); } } } diff --git a/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs b/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs index 1fb911bdd..ca04f2b45 100644 --- a/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs @@ -12,6 +12,7 @@ namespace ImageProcessor.Formats { using System; using System.IO; + using System.Threading.Tasks; /// /// Performs the bmp decoding operation. @@ -194,7 +195,7 @@ namespace ImageProcessor.Formats // Bit mask int mask = 0xFF >> (8 - bits); - byte[] data = new byte[(arrayWidth * height)]; + byte[] data = new byte[arrayWidth * height]; this.currentStream.Read(data, 0, data.Length); @@ -205,31 +206,34 @@ namespace ImageProcessor.Formats alignment = 4 - alignment; } - for (int y = 0; y < height; y++) - { - int rowOffset = y * (arrayWidth + alignment); + Parallel.For( + 0, + height, + y => + { + int rowOffset = y * (arrayWidth + alignment); - for (int x = 0; x < arrayWidth; x++) - { - int offset = rowOffset + x; + for (int x = 0; x < arrayWidth; x++) + { + int offset = rowOffset + x; - // Revert the y value, because bitmaps are saved from down to top - int row = Invert(y, height); + // Revert the y value, because bitmaps are saved from down to top + int row = Invert(y, height); - int colOffset = x * ppb; + int colOffset = x * ppb; - for (int shift = 0; shift < ppb && (colOffset + shift) < width; shift++) - { - int colorIndex = (data[offset] >> (8 - bits - (shift * bits))) & mask; + for (int shift = 0; shift < ppb && (colOffset + shift) < width; shift++) + { + int colorIndex = (data[offset] >> (8 - bits - (shift * bits))) & mask; - int arrayOffset = ((row * width) + (colOffset + shift)) * 4; - imageData[arrayOffset + 0] = colors[colorIndex * 4]; - imageData[arrayOffset + 1] = colors[(colorIndex * 4) + 1]; - imageData[arrayOffset + 2] = colors[(colorIndex * 4) + 2]; - imageData[arrayOffset + 3] = 255; - } - } - } + int arrayOffset = ((row * width) + (colOffset + shift)) * 4; + imageData[arrayOffset + 0] = colors[colorIndex * 4]; + imageData[arrayOffset + 1] = colors[(colorIndex * 4) + 1]; + imageData[arrayOffset + 2] = colors[(colorIndex * 4) + 2]; + imageData[arrayOffset + 3] = 255; + } + } + }); } /// diff --git a/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs b/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs index ed833bf62..bbb2d6538 100644 --- a/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs @@ -7,6 +7,7 @@ namespace ImageProcessor.Formats { using System; using System.IO; + using System.Threading.Tasks; /// /// Image encoder for writing an image to a stream as a Windows bitmap. diff --git a/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs b/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs index 766923f7e..587a1bf18 100644 --- a/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs +++ b/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs @@ -7,6 +7,8 @@ namespace ImageProcessor.Formats { using System; using System.IO; + using System.Threading.Tasks; + using BitMiracle.LibJpeg; /// @@ -104,43 +106,34 @@ namespace ImageProcessor.Formats throw new NotSupportedException("JpegDecoder only support RGB color space."); } - for (int y = 0; y < pixelHeight; y++) - { - SampleRow row = jpg.GetRow(y); + Parallel.For( + 0, + pixelHeight, + y => + { + SampleRow row = jpg.GetRow(y); - for (int x = 0; x < pixelWidth; x++) - { - Sample sample = row.GetAt(x); + for (int x = 0; x < pixelWidth; x++) + { + Sample sample = row.GetAt(x); - int offset = ((y * pixelWidth) + x) * 4; + int offset = ((y * pixelWidth) + x) * 4; - pixels[offset + 0] = (byte)sample[2]; - pixels[offset + 1] = (byte)sample[1]; - pixels[offset + 2] = (byte)sample[0]; - pixels[offset + 3] = 255; - } - } + pixels[offset + 0] = (byte)sample[2]; + pixels[offset + 1] = (byte)sample[1]; + pixels[offset + 2] = (byte)sample[0]; + pixels[offset + 3] = 255; + } + }); image.SetPixels(pixelWidth, pixelHeight, pixels); } /// - /// + /// Returns a value indicating whether the given bytes identify Jpeg data. /// - /// - /// - private bool IsExif(byte[] header) - { - bool isExif = - header[6] == 0x45 && // E - header[7] == 0x78 && // x - header[8] == 0x69 && // i - header[9] == 0x66 && // f - header[10] == 0x00; - - return isExif; - } - + /// The bytes representing the file header. + /// The private static bool IsJpeg(byte[] header) { bool isJpg = @@ -152,5 +145,22 @@ namespace ImageProcessor.Formats return isJpg; } + + /// + /// Returns a value indicating whether the given bytes identify EXIF data. + /// + /// The bytes representing the file header. + /// The + private bool IsExif(byte[] header) + { + bool isExif = + header[6] == 0x45 && // E + header[7] == 0x78 && // x + header[8] == 0x69 && // i + header[9] == 0x66 && // f + header[10] == 0x00; + + return isExif; + } } } diff --git a/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs b/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs index 35d6e286e..60971697c 100644 --- a/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs +++ b/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs @@ -7,6 +7,7 @@ namespace ImageProcessor.Formats { using System; using System.IO; + using System.Threading.Tasks; using BitMiracle.LibJpeg; @@ -92,22 +93,25 @@ namespace ImageProcessor.Formats SampleRow[] rows = new SampleRow[pixelHeight]; - for (int y = 0; y < pixelHeight; y++) - { - byte[] samples = new byte[pixelWidth * 3]; - - for (int x = 0; x < pixelWidth; x++) - { - int start = x * 3; - int source = ((y * pixelWidth) + x) * 4; - - samples[start] = sourcePixels[source + 2]; - samples[start + 1] = sourcePixels[source + 1]; - samples[start + 2] = sourcePixels[source]; - } - - rows[y] = new SampleRow(samples, pixelWidth, 8, 3); - } + Parallel.For( + 0, + pixelHeight, + y => + { + byte[] samples = new byte[pixelWidth * 3]; + + for (int x = 0; x < pixelWidth; x++) + { + int start = x * 3; + int source = ((y * pixelWidth) + x) * 4; + + samples[start] = sourcePixels[source + 2]; + samples[start + 1] = sourcePixels[source + 1]; + samples[start + 2] = sourcePixels[source]; + } + + rows[y] = new SampleRow(samples, pixelWidth, 8, 3); + }); JpegImage jpg = new JpegImage(rows, Colorspace.RGB); jpg.WriteJpeg(stream, new CompressionParameters { Quality = this.Quality }); diff --git a/src/ImageProcessor/Formats/Png/Zlib/InflaterInputBuffer.cs b/src/ImageProcessor/Formats/Png/Zlib/InflaterInputBuffer.cs index 42fa1753a..5c70ad41c 100644 --- a/src/ImageProcessor/Formats/Png/Zlib/InflaterInputBuffer.cs +++ b/src/ImageProcessor/Formats/Png/Zlib/InflaterInputBuffer.cs @@ -3,9 +3,6 @@ using System; using System.IO; - //using ICSharpCode.SharpZipLib.Zip; - //using ICSharpCode.SharpZipLib.Zip.Compression; - /// /// An input buffer customised for use by /// @@ -14,7 +11,6 @@ /// public class InflaterInputBuffer { - #region Constructors /// /// Initialise a new instance of with a default buffer size /// @@ -39,7 +35,6 @@ rawData = new byte[bufferSize]; clearText = rawData; } - #endregion /// /// Get the length of bytes bytes in the @@ -127,17 +122,7 @@ toRead -= count; } -#if !NETCF_1_0 && !NOCRYPTO - if (cryptoTransform != null) - { - clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0); - } - else -#endif - { - clearTextLength = rawLength; - } - + clearTextLength = rawLength; available = clearTextLength; } @@ -178,12 +163,14 @@ return 0; } } + int toCopy = Math.Min(currentLength, available); - System.Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy); + Array.Copy(rawData, rawLength - (int)available, outBuffer, currentOffset, toCopy); currentOffset += toCopy; currentLength -= toCopy; available -= toCopy; } + return length; } @@ -270,57 +257,12 @@ return (uint)ReadLeInt() | ((long)ReadLeInt() << 32); } -#if !NETCF_1_0 && !NOCRYPTO - /// - /// Get/set the to apply to any data. - /// - /// Set this value to null to have no transform applied. - public ICryptoTransform CryptoTransform - { - set - { - cryptoTransform = value; - if (cryptoTransform != null) - { - if (rawData == clearText) - { - if (internalClearText == null) - { - internalClearText = new byte[rawData.Length]; - } - clearText = internalClearText; - } - clearTextLength = rawLength; - if (available > 0) - { - cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available); - } - } - else - { - clearText = rawData; - clearTextLength = rawLength; - } - } - } -#endif - - #region Instance Fields int rawLength; byte[] rawData; int clearTextLength; byte[] clearText; -#if !NETCF_1_0 && !NOCRYPTO - byte[] internalClearText; -#endif - int available; - -#if !NETCF_1_0 && !NOCRYPTO - ICryptoTransform cryptoTransform; -#endif Stream inputStream; - #endregion } } diff --git a/src/ImageProcessor/Formats/Png/Zlib/InflaterInputStream.cs b/src/ImageProcessor/Formats/Png/Zlib/InflaterInputStream.cs index 62cba8bb4..b6a35e420 100644 --- a/src/ImageProcessor/Formats/Png/Zlib/InflaterInputStream.cs +++ b/src/ImageProcessor/Formats/Png/Zlib/InflaterInputStream.cs @@ -149,16 +149,6 @@ } } - /// - /// Clear any cryptographic state. - /// - protected void StopDecrypting() - { -#if !NETCF_1_0 && !NOCRYPTO - inputBuffer.CryptoTransform = null; -#endif - } - /// /// Returns 0 once the end of the stream (EOF) has been reached. /// Otherwise returns 1. diff --git a/src/ImageProcessor/Formats/Png/Zlib/ZipConstants.cs b/src/ImageProcessor/Formats/Png/Zlib/ZipConstants.cs index 6dccc6a96..9ba46abe4 100644 --- a/src/ImageProcessor/Formats/Png/Zlib/ZipConstants.cs +++ b/src/ImageProcessor/Formats/Png/Zlib/ZipConstants.cs @@ -7,7 +7,6 @@ /// public static class ZipConstants { - #region Versions /// /// The version made by field for entries in the central header when created by this library /// @@ -30,9 +29,7 @@ /// The version required for Zip64 extensions (4.5 or higher) /// public const int VersionZip64 = 45; - #endregion - #region Header Sizes /// /// Size of local entry header (excluding variable length fields at end) /// @@ -62,9 +59,7 @@ /// Size of 'classic' cryptographic header stored before any entry data /// public const int CryptoHeaderSize = 12; - #endregion - #region Header Signatures /// /// Signature for local entry header @@ -121,52 +116,8 @@ /// End of central directory record signature /// public const int EndOfCentralDirectorySignature = 'P' | ('K' << 8) | (5 << 16) | (6 << 24); - - #endregion - -#if NETCF_1_0 || NETCF_2_0 - // This isnt so great but is better than nothing. - // Trying to work out an appropriate OEM code page would be good. - // 850 is a good default for english speakers particularly in Europe. - static int defaultCodePage = CultureInfo.CurrentCulture.TextInfo.ANSICodePage; -#elif PCL static Encoding defaultEncoding = Encoding.UTF8; -#else - /// - /// Get OEM codepage from NetFX, which parses the NLP file with culture info table etc etc. - /// But sometimes it yields the special value of 1 which is nicknamed CodePageNoOEM in sources (might also mean CP_OEMCP, but Encoding puts it so). - /// This was observed on Ukranian and Hindu systems. - /// Given this value, throws an . - /// So replace it with some fallback, e.g. 437 which is the default cpcp in a console in a default Windows installation. - /// - static int defaultCodePage = - // these values cause ArgumentException in subsequent calls to Encoding::GetEncoding() - ((Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 1) || (Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 2) || (Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 3) || (Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage == 42)) - ? 437 // The default OEM encoding in a console in a default Windows installation, as a fallback. - : Thread.CurrentThread.CurrentCulture.TextInfo.OEMCodePage; -#endif -#if !PCL - /// - /// Default encoding used for string conversion. 0 gives the default system OEM code page. - /// Dont use unicode encodings if you want to be Zip compatible! - /// Using the default code page isnt the full solution neccessarily - /// there are many variable factors, codepage 850 is often a good choice for - /// European users, however be careful about compatability. - /// - public static int DefaultCodePage { - get { - return defaultCodePage; - } - set { - if ((value < 0) || (value > 65535) || - (value == 1) || (value == 2) || (value == 3) || (value == 42)) { - throw new ArgumentOutOfRangeException("value"); - } - - defaultCodePage = value; - } - } -#else + /// /// PCL don't support CodePage so we used Encoding instead of /// @@ -176,12 +127,12 @@ { return defaultEncoding; } + set { defaultEncoding = value; } } -#endif /// /// Convert a portion of a byte array to a string. @@ -201,11 +152,8 @@ { return string.Empty; } -#if !PCL - return Encoding.GetEncoding(DefaultCodePage).GetString(data, 0, count); -#else + return DefaultEncoding.GetString(data, 0, count); -#endif } /// @@ -294,11 +242,8 @@ { return new byte[0]; } -#if !PCL - return Encoding.GetEncoding(DefaultCodePage).GetBytes(str); -#else + return DefaultEncoding.GetBytes(str); -#endif } /// @@ -320,10 +265,8 @@ { return Encoding.UTF8.GetBytes(str); } - else - { - return ConvertToArray(str); - } + + return ConvertToArray(str); } } } diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 77ea223ad..0c53f80f1 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -42,6 +42,8 @@ + + diff --git a/src/ImageProcessor/Samplers/Resize - Copy.cs b/src/ImageProcessor/Samplers/Resize - Copy.cs new file mode 100644 index 000000000..d94b3753e --- /dev/null +++ b/src/ImageProcessor/Samplers/Resize - Copy.cs @@ -0,0 +1,232 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Samplers +{ + using System; + using System.Collections.Generic; + using System.Threading.Tasks; + + /// + /// Provides methods that allow the resizing of images using various resampling algorithms. + /// + public class Resize : ParallelImageProcessor + { + /// + /// The epsilon for comparing floating point numbers. + /// + private const float Epsilon = 0.0001f; + + /// + /// The horizontal weights. + /// + private Weights[] horizontalWeights; + + /// + /// The vertical weights. + /// + private Weights[] verticalWeights; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The sampler to perform the resize operation. + /// + public Resize(IResampler sampler) + { + Guard.NotNull(sampler, nameof(sampler)); + + this.Sampler = sampler; + } + + /// + /// Gets the sampler to perform the resize operation. + /// + public IResampler Sampler { get; } + + /// + protected override void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle) + { + this.horizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width); + this.verticalWeights = this.PrecomputeWeights(targetRectangle.Height, sourceRectangle.Height); + } + + /// + protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + { + int targetY = targetRectangle.Y; + int targetBottom = targetRectangle.Bottom; + int startX = targetRectangle.X; + int endX = targetRectangle.Right; + + Parallel.For( + startY, + endY, + y => + { + if (y >= targetY && y < targetBottom) + { + List verticalValues = this.verticalWeights[y].Values; + double verticalSum = this.verticalWeights[y].Sum; + + for (int x = startX; x < endX; x++) + { + List horizontalValues = this.horizontalWeights[x].Values; + double horizontalSum = this.horizontalWeights[x].Sum; + + // Destination color components + double r = 0; + double g = 0; + double b = 0; + double a = 0; + + foreach (Weight yw in verticalValues) + { + if (Math.Abs(yw.Value) < Epsilon) + { + continue; + } + + int originY = yw.Index; + + foreach (Weight xw in horizontalValues) + { + if (Math.Abs(xw.Value) < Epsilon) + { + continue; + } + + int originX = xw.Index; + Bgra sourceColor = source[originX, originY]; + //ColorVector sourceColor = PixelOperations.ToLinear(source[originX, originY]); + + r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + b += sourceColor.B * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + a += sourceColor.A * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + } + } + + // TODO: Double cast. + Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte()); + //Bgra destinationColor = PixelOperations.ToSrgb(new ColorVector(b, g, r, a)); + target[x, y] = destinationColor; + } + } + }); + } + + /// + /// Computes the weights to apply at each pixel when resizing. + /// + /// The destination section size. + /// The source section size. + /// + /// The . + /// + private Weights[] PrecomputeWeights(int destinationSize, int sourceSize) + { + IResampler sampler = this.Sampler; + double du = sourceSize / (double)destinationSize; + double scale = du; + + if (scale < 1) + { + scale = 1; + } + + double ru = Math.Ceiling(scale * sampler.Radius); + Weights[] result = new Weights[destinationSize]; + + for (int i = 0; i < destinationSize; i++) + { + double fu = ((i + .5) * du) - 0.5; + int startU = (int)Math.Ceiling(fu - ru); + + if (startU < 0) + { + startU = 0; + } + + int endU = (int)Math.Floor(fu + ru); + + if (endU > sourceSize - 1) + { + endU = sourceSize - 1; + } + + double sum = 0; + result[i] = new Weights(); + + for (int a = startU; a <= endU; a++) + { + double w = 255 * sampler.GetValue((a - fu) / scale); + + if (Math.Abs(w) > Epsilon) + { + sum += w; + result[i].Values.Add(new Weight(a, w)); + } + } + + result[i].Sum = sum; + } + + return result; + } + + /// + /// Represents the weight to be added to a scaled pixel. + /// + protected struct Weight + { + /// + /// The pixel index. + /// + public readonly int Index; + + /// + /// The result of the interpolation algorithm. + /// + public readonly double Value; + + /// + /// Initializes a new instance of the struct. + /// + /// The index. + /// The value. + public Weight(int index, double value) + { + this.Index = index; + this.Value = value; + } + } + + /// + /// Represents a collection of weights and their sum. + /// + protected class Weights + { + /// + /// Initializes a new instance of the class. + /// + public Weights() + { + this.Values = new List(); + } + + /// + /// Gets or sets the values. + /// + public List Values { get; set; } + + /// + /// Gets or sets the sum. + /// + public double Sum { get; set; } + } + } +} diff --git a/src/ImageProcessor/Samplers/Resize.cs b/src/ImageProcessor/Samplers/Resize.cs index 015f6d2d7..1010aa17c 100644 --- a/src/ImageProcessor/Samplers/Resize.cs +++ b/src/ImageProcessor/Samplers/Resize.cs @@ -7,6 +7,7 @@ namespace ImageProcessor.Samplers { using System; using System.Collections.Generic; + using System.Threading.Tasks; /// /// Provides methods that allow the resizing of images using various resampling algorithms. @@ -61,57 +62,61 @@ namespace ImageProcessor.Samplers int startX = targetRectangle.X; int endX = targetRectangle.Right; - for (int y = startY; y < endY; y++) - { - if (y >= targetY && y < targetBottom) + Parallel.For( + startY, + endY, + y => { - List verticalValues = this.verticalWeights[y].Values; - double verticalSum = this.verticalWeights[y].Sum; - - for (int x = startX; x < endX; x++) + if (y >= targetY && y < targetBottom) { - List horizontalValues = this.horizontalWeights[x].Values; - double horizontalSum = this.horizontalWeights[x].Sum; + List verticalValues = this.verticalWeights[y].Values; + double verticalSum = this.verticalWeights[y].Sum; - // Destination color components - double r = 0; - double g = 0; - double b = 0; - double a = 0; - - foreach (Weight yw in verticalValues) + for (int x = startX; x < endX; x++) { - if (Math.Abs(yw.Value) < Epsilon) - { - continue; - } + List horizontalValues = this.horizontalWeights[x].Values; + double horizontalSum = this.horizontalWeights[x].Sum; - int originY = yw.Index; + // Destination color components + double r = 0; + double g = 0; + double b = 0; + double a = 0; - foreach (Weight xw in horizontalValues) + foreach (Weight yw in verticalValues) { - if (Math.Abs(xw.Value) < Epsilon) + if (Math.Abs(yw.Value) < Epsilon) { continue; } - int originX = xw.Index; - Bgra sourceColor = source[originX, originY]; - sourceColor = PixelOperations.ToLinear(sourceColor); + int originY = yw.Index; - r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - b += sourceColor.B * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - a += sourceColor.A * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + foreach (Weight xw in horizontalValues) + { + if (Math.Abs(xw.Value) < Epsilon) + { + continue; + } + + int originX = xw.Index; + Bgra sourceColor = source[originX, originY]; + //ColorVector sourceColor = PixelOperations.ToLinear(source[originX, originY]); + + r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + b += sourceColor.B * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + a += sourceColor.A * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + } } - } - Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte()); - destinationColor = PixelOperations.ToSrgb(destinationColor); - target[x, y] = destinationColor; + // TODO: Double cast. + Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte()); + //Bgra destinationColor = PixelOperations.ToSrgb(new ColorVector(b, g, r, a)); + target[x, y] = destinationColor; + } } - } - } + }); } /// @@ -136,39 +141,42 @@ namespace ImageProcessor.Samplers double ru = Math.Ceiling(scale * sampler.Radius); Weights[] result = new Weights[destinationSize]; - for (int i = 0; i < destinationSize; i++) - { - double fu = ((i + .5) * du) - 0.5; - int startU = (int)Math.Ceiling(fu - ru); + Parallel.For( + 0, + destinationSize, + i => + { + double fu = ((i + .5) * du) - 0.5; + int startU = (int)Math.Ceiling(fu - ru); - if (startU < 0) - { - startU = 0; - } + if (startU < 0) + { + startU = 0; + } - int endU = (int)Math.Floor(fu + ru); + int endU = (int)Math.Floor(fu + ru); - if (endU > sourceSize - 1) - { - endU = sourceSize - 1; - } + if (endU > sourceSize - 1) + { + endU = sourceSize - 1; + } - double sum = 0; - result[i] = new Weights(); + double sum = 0; + result[i] = new Weights(); - for (int a = startU; a <= endU; a++) - { - double w = 255 * sampler.GetValue((a - fu) / scale); + for (int a = startU; a <= endU; a++) + { + double w = 255 * sampler.GetValue((a - fu) / scale); - if (Math.Abs(w) > Epsilon) - { - sum += w; - result[i].Values.Add(new Weight(a, w)); - } - } + if (Math.Abs(w) > Epsilon) + { + sum += w; + result[i].Values.Add(new Weight(a, w)); + } + } - result[i].Sum = sum; - } + result[i].Sum = sum; + }); return result; } diff --git a/tests/ImageProcessor.Tests/ImageProcessor.Tests.csproj b/tests/ImageProcessor.Tests/ImageProcessor.Tests.csproj index fd13cac0e..ff06126e0 100644 --- a/tests/ImageProcessor.Tests/ImageProcessor.Tests.csproj +++ b/tests/ImageProcessor.Tests/ImageProcessor.Tests.csproj @@ -10,13 +10,14 @@ Properties ImageProcessor.Tests ImageProcessor.Tests - v4.5 + v4.6 512 {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} ..\..\ true + true @@ -37,6 +38,11 @@ + + + ..\..\packages\System.Numerics.Vectors.4.1.0\lib\net46\System.Numerics.Vectors.dll + True + ..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll True diff --git a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs index 34c8656cd..07d9f5e25 100644 --- a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs +++ b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs @@ -19,15 +19,15 @@ namespace ImageProcessor.Tests /// public static readonly List Files = new List { - //"../../TestImages/Formats/Jpg/Backdrop.jpg", - //"../../TestImages/Formats/Jpg/Calliphora.jpg", - //"../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg", + "../../TestImages/Formats/Jpg/Backdrop.jpg", + "../../TestImages/Formats/Jpg/Calliphora.jpg", + "../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg", "../../TestImages/Formats/Jpg/greyscale.jpg", - //"../../TestImages/Formats/Bmp/Car.bmp", - //"../../TestImages/Formats/Png/cmyk.png", - //"../../TestImages/Formats/Png/gamma-1.0-or-2.2.png", - //"../../TestImages/Formats/Gif/leaf.gif", - //"../../TestImages/Formats/Gif/rings.gif" + "../../TestImages/Formats/Bmp/Car.bmp", + "../../TestImages/Formats/Png/cmyk.png", + "../../TestImages/Formats/Png/gamma-1.0-or-2.2.png", + "../../TestImages/Formats/Gif/leaf.gif", + "../../TestImages/Formats/Gif/rings.gif" // { "../../TestImages/Formats/Gif/ani.gif" }, // { "../../TestImages/Formats/Gif/ani2.gif" }, diff --git a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs index 49ad6576b..cd42165c8 100644 --- a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs @@ -1,6 +1,7 @@  namespace ImageProcessor.Tests { + using System; using System.Diagnostics; using System.IO; diff --git a/tests/ImageProcessor.Tests/packages.config b/tests/ImageProcessor.Tests/packages.config index 3ef6ebb2a..8cba8428f 100644 --- a/tests/ImageProcessor.Tests/packages.config +++ b/tests/ImageProcessor.Tests/packages.config @@ -1,5 +1,10 @@  + + + + + From c723c10b33cb150c0c3e8b3017afce3f183bf55b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 29 Oct 2015 07:58:59 +1100 Subject: [PATCH 02/15] Attempt to speed up operations using vectors. Former-commit-id: a28745bb3a7a48769718459f660aee59dc6727fd Former-commit-id: 3cea324866d570efa674f7ea8cfcf964a3283f58 Former-commit-id: 8eb414b88e6c70055d2653818694c0fc8c95ba83 --- src/ImageProcessor/Colors/Bgra.cs | 2 +- .../Common/Helpers/PixelOperations - Copy.cs | 193 ++++++++++++++++++ .../Common/Helpers/PixelOperations.cs | 34 +-- src/ImageProcessor/Samplers/Resize.cs | 11 +- .../Processors/ProcessorTestBase.cs | 16 +- 5 files changed, 226 insertions(+), 30 deletions(-) create mode 100644 src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs diff --git a/src/ImageProcessor/Colors/Bgra.cs b/src/ImageProcessor/Colors/Bgra.cs index 861e75c0b..25b703f6f 100644 --- a/src/ImageProcessor/Colors/Bgra.cs +++ b/src/ImageProcessor/Colors/Bgra.cs @@ -194,7 +194,7 @@ namespace ImageProcessor /// public static implicit operator Bgra(ColorVector color) { - return new Bgra((255 * color.B).ToByte(), (255 * color.G).ToByte(), (255 * color.R).ToByte(), (255 * color.A).ToByte()); + return new Bgra((255f * color.B).ToByte(), (255f * color.G).ToByte(), (255f * color.R).ToByte(), (255f * color.A).ToByte()); } /// diff --git a/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs b/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs new file mode 100644 index 000000000..a876b45ef --- /dev/null +++ b/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs @@ -0,0 +1,193 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor +{ + using System; + + /// + /// Performs per-pixel operations. + /// + public static class PixelOperations + { + /// + /// The array of bytes representing each possible value of color component + /// converted from sRGB to the linear color space. + /// + private static readonly Lazy LinearBytes = new Lazy(GetLinearBytes); + + /// + /// The array of bytes representing each possible value of color component + /// converted from linear to the sRGB color space. + /// + private static readonly Lazy SrgbBytes = new Lazy(GetSrgbBytes); + + /// + /// The array of bytes representing each possible value of color component + /// converted from gamma to the linear color space. + /// + private static readonly Lazy LinearGammaBytes = new Lazy(GetLinearGammaBytes); + + /// + /// The array of bytes representing each possible value of color component + /// converted from linear to the gamma color space. + /// + private static readonly Lazy GammaLinearBytes = new Lazy(GetGammaLinearBytes); + + /// + /// Converts an pixel from an sRGB color-space to the equivalent linear color-space. + /// + /// + /// The to convert. + /// + /// + /// The . + /// + public static Bgra ToLinear(Bgra composite) + { + // Create only once and lazily. + // byte[] ramp = LinearGammaBytes.Value; + byte[] ramp = LinearBytes.Value; + + return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A); + } + + /// + /// Converts a pixel from a linear color-space to the equivalent sRGB color-space. + /// + /// + /// The to convert. + /// + /// + /// The . + /// + public static Bgra ToSrgb(Bgra linear) + { + // Create only once and lazily. + // byte[] ramp = GammaLinearBytes.Value; + byte[] ramp = SrgbBytes.Value; + + return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A); + } + + /// + /// Gets an array of bytes representing each possible value of color component + /// converted from sRGB to the linear color space. + /// + /// + /// The . + /// + private static byte[] GetLinearBytes() + { + byte[] ramp = new byte[256]; + for (int x = 0; x < 256; ++x) + { + byte val = (255f * SrgbToLinear(x / 255f)).ToByte(); + ramp[x] = val; + } + + return ramp; + } + + /// + /// Gets an array of bytes representing each possible value of color component + /// converted from linear to the sRGB color space. + /// + /// + /// The . + /// + private static byte[] GetSrgbBytes() + { + byte[] ramp = new byte[256]; + for (int x = 0; x < 256; ++x) + { + byte val = (255f * LinearToSrgb(x / 255f)).ToByte(); + ramp[x] = val; + } + + return ramp; + } + + /// + /// Gets the correct linear value from an sRGB signal. + /// + /// + /// + /// The signal value to convert. + /// + /// The . + /// + private static float SrgbToLinear(float signal) + { + float a = 0.055f; + + if (signal <= 0.04045) + { + return signal / 12.92f; + } + + return (float)Math.Pow((signal + a) / (1 + a), 2.4); + } + + /// + /// Gets the correct sRGB value from an linear signal. + /// + /// + /// + /// The signal value to convert. + /// + /// The . + /// + private static float LinearToSrgb(float signal) + { + float a = 0.055f; + + if (signal <= 0.0031308) + { + return signal * 12.92f; + } + + return ((float)((1 + a) * Math.Pow(signal, 1 / 2.4f))) - a; + } + + /// + /// Gets an array of bytes representing each possible value of color component + /// converted from gamma to the linear color space. + /// + /// + /// The . + /// + private static byte[] GetLinearGammaBytes() + { + byte[] ramp = new byte[256]; + for (int x = 0; x < 256; ++x) + { + byte val = (255f * Math.Pow(x / 255f, 2.2)).ToByte(); + ramp[x] = val; + } + + return ramp; + } + + /// + /// Gets an array of bytes representing each possible value of color component + /// converted from linear to the gamma color space. + /// + /// + /// The . + /// + private static byte[] GetGammaLinearBytes() + { + byte[] ramp = new byte[256]; + for (int x = 0; x < 256; ++x) + { + byte val = (255f * Math.Pow(x / 255f, 1 / 2.2)).ToByte(); + ramp[x] = val; + } + + return ramp; + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Common/Helpers/PixelOperations.cs b/src/ImageProcessor/Common/Helpers/PixelOperations.cs index a876b45ef..0a9c43797 100644 --- a/src/ImageProcessor/Common/Helpers/PixelOperations.cs +++ b/src/ImageProcessor/Common/Helpers/PixelOperations.cs @@ -13,16 +13,16 @@ namespace ImageProcessor public static class PixelOperations { /// - /// The array of bytes representing each possible value of color component + /// The array of values representing each possible value of color component /// converted from sRGB to the linear color space. /// - private static readonly Lazy LinearBytes = new Lazy(GetLinearBytes); + private static readonly Lazy LinearLut = new Lazy(GetLinearBytes); /// - /// The array of bytes representing each possible value of color component + /// The array of values representing each possible value of color component /// converted from linear to the sRGB color space. /// - private static readonly Lazy SrgbBytes = new Lazy(GetSrgbBytes); + private static readonly Lazy SrgbLut = new Lazy(GetSrgbBytes); /// /// The array of bytes representing each possible value of color component @@ -45,13 +45,14 @@ namespace ImageProcessor /// /// The . /// - public static Bgra ToLinear(Bgra composite) + public static Bgra ToLinear(ColorVector composite) { // Create only once and lazily. // byte[] ramp = LinearGammaBytes.Value; - byte[] ramp = LinearBytes.Value; + float[] ramp = LinearLut.Value; - return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A); + // TODO: This just doesn't seem right to me. + return new ColorVector(ramp[(composite.B * 255).ToByte()], ramp[(composite.G * 255).ToByte()], ramp[(composite.R * 255).ToByte()], composite.A); } /// @@ -63,13 +64,14 @@ namespace ImageProcessor /// /// The . /// - public static Bgra ToSrgb(Bgra linear) + public static Bgra ToSrgb(ColorVector linear) { // Create only once and lazily. // byte[] ramp = GammaLinearBytes.Value; - byte[] ramp = SrgbBytes.Value; + float[] ramp = SrgbLut.Value; - return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A); + // TODO: This just doesn't seem right to me. + return new ColorVector(ramp[(linear.B * 255).ToByte()], ramp[(linear.G * 255).ToByte()], (linear.R * 255).ToByte(), linear.A); } /// @@ -79,12 +81,12 @@ namespace ImageProcessor /// /// The . /// - private static byte[] GetLinearBytes() + private static float[] GetLinearBytes() { - byte[] ramp = new byte[256]; + float[] ramp = new float[256]; for (int x = 0; x < 256; ++x) { - byte val = (255f * SrgbToLinear(x / 255f)).ToByte(); + float val = SrgbToLinear(x / 255f); ramp[x] = val; } @@ -98,12 +100,12 @@ namespace ImageProcessor /// /// The . /// - private static byte[] GetSrgbBytes() + private static float[] GetSrgbBytes() { - byte[] ramp = new byte[256]; + float[] ramp = new float[256]; for (int x = 0; x < 256; ++x) { - byte val = (255f * LinearToSrgb(x / 255f)).ToByte(); + float val = LinearToSrgb(x / 255f); ramp[x] = val; } diff --git a/src/ImageProcessor/Samplers/Resize.cs b/src/ImageProcessor/Samplers/Resize.cs index 1010aa17c..057aedf83 100644 --- a/src/ImageProcessor/Samplers/Resize.cs +++ b/src/ImageProcessor/Samplers/Resize.cs @@ -7,6 +7,7 @@ namespace ImageProcessor.Samplers { using System; using System.Collections.Generic; + using System.Numerics; using System.Threading.Tasks; /// @@ -61,6 +62,7 @@ namespace ImageProcessor.Samplers int targetBottom = targetRectangle.Bottom; int startX = targetRectangle.X; int endX = targetRectangle.Right; + //Vector endVX = new Vector(targetRectangle.Right); Parallel.For( startY, @@ -100,8 +102,8 @@ namespace ImageProcessor.Samplers } int originX = xw.Index; - Bgra sourceColor = source[originX, originY]; - //ColorVector sourceColor = PixelOperations.ToLinear(source[originX, originY]); + ColorVector sourceColor = source[originX, originY]; + //sourceColor = PixelOperations.ToLinear(sourceColor); r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum); g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum); @@ -110,9 +112,8 @@ namespace ImageProcessor.Samplers } } - // TODO: Double cast. - Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte()); - //Bgra destinationColor = PixelOperations.ToSrgb(new ColorVector(b, g, r, a)); + // TODO: Double cast? + Bgra destinationColor = new ColorVector(b, g, r, a);//PixelOperations.ToSrgb(new ColorVector(b, g, r, a)); target[x, y] = destinationColor; } } diff --git a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs index 07d9f5e25..cb22fe8db 100644 --- a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs +++ b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs @@ -20,14 +20,14 @@ namespace ImageProcessor.Tests public static readonly List Files = new List { "../../TestImages/Formats/Jpg/Backdrop.jpg", - "../../TestImages/Formats/Jpg/Calliphora.jpg", - "../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg", - "../../TestImages/Formats/Jpg/greyscale.jpg", - "../../TestImages/Formats/Bmp/Car.bmp", - "../../TestImages/Formats/Png/cmyk.png", - "../../TestImages/Formats/Png/gamma-1.0-or-2.2.png", - "../../TestImages/Formats/Gif/leaf.gif", - "../../TestImages/Formats/Gif/rings.gif" + //"../../TestImages/Formats/Jpg/Calliphora.jpg", + //"../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg", + //"../../TestImages/Formats/Jpg/greyscale.jpg", + //"../../TestImages/Formats/Bmp/Car.bmp", + //"../../TestImages/Formats/Png/cmyk.png", + //"../../TestImages/Formats/Png/gamma-1.0-or-2.2.png", + //"../../TestImages/Formats/Gif/leaf.gif", + //"../../TestImages/Formats/Gif/rings.gif" // { "../../TestImages/Formats/Gif/ani.gif" }, // { "../../TestImages/Formats/Gif/ani2.gif" }, From 70f90573467a9b0ae39ee60e3709032b64c22e0f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Oct 2015 00:52:25 +1100 Subject: [PATCH 03/15] Reshuffle colors, improve accuracy of cspace conversion Former-commit-id: 21db4ab00e856eae2f405ef0fba5637db1a309ac Former-commit-id: 6e9b3dd6524e5d7c811547f2808a95c720fe02b6 Former-commit-id: 291d39f6d5dcfed05b49bbfda0f78e4f48112d7f --- src/ImageProcessor/ApiPortabilityAnalysis.htm | 218 --------------- src/ImageProcessor/Colors/Color.cs | 249 ++++++++++++++++++ src/ImageProcessor/Colors/ColorVector.cs | 132 ---------- .../Colors/{Bgra.cs => Formats/Bgra32.cs} | 125 +++++---- .../Colors/{ => Formats}/Cmyk.cs | 6 +- .../Colors/{ => Formats}/Hsv.cs | 6 +- .../Colors/{ => Formats}/YCbCr.cs | 6 +- .../Common/Helpers/ImageMaths.cs | 32 ++- .../Common/Helpers/PixelOperations - Copy.cs | 193 -------------- .../Common/Helpers/PixelOperations.cs | 145 ++-------- src/ImageProcessor/Filters/Alpha.cs | 4 +- .../Filters/ColorMatrix/ColorMatrixFilter.cs | 13 +- src/ImageProcessor/Filters/Contrast.cs | 4 +- src/ImageProcessor/Filters/Invert.cs | 4 +- src/ImageProcessor/Formats/Gif/GifEncoder.cs | 4 +- .../Formats/Gif/Quantizer/OctreeQuantizer.cs | 34 +-- .../Formats/Gif/Quantizer/QuantizedImage.cs | 6 +- .../Formats/Gif/Quantizer/Quantizer.cs | 12 +- src/ImageProcessor/IImageBase.cs | 4 +- src/ImageProcessor/ImageBase.cs | 6 +- src/ImageProcessor/ImageProcessor.csproj | 12 +- .../ImageProcessor.csproj.DotSettings | 1 + .../Samplers/Resamplers/BicubicResampler.cs | 12 +- .../Samplers/Resamplers/BoxResampler.cs | 4 +- .../Resamplers/CatmullRomResampler.cs | 8 +- .../Samplers/Resamplers/HermiteResampler.cs | 8 +- .../Samplers/Resamplers/IResampler.cs | 15 +- .../Samplers/Resamplers/Lanczos3Resampler.cs | 4 +- .../Samplers/Resamplers/Lanczos5Resampler.cs | 4 +- .../Samplers/Resamplers/Lanczos8Resampler.cs | 4 +- .../Resamplers/MitchellNetravaliResampler.cs | 8 +- .../Samplers/Resamplers/RobidouxResampler.cs | 8 +- .../Resamplers/RobidouxSharpResampler.cs | 8 +- .../Resamplers/RobidouxSoftResampler.cs | 8 +- .../Samplers/Resamplers/SplineResampler.cs | 8 +- .../Samplers/Resamplers/TriangleResampler.cs | 4 +- .../Samplers/Resamplers/WelchResampler.cs | 6 +- src/ImageProcessor/Samplers/Resize - Copy.cs | 232 ---------------- src/ImageProcessor/Samplers/Resize.cs | 48 ++-- .../Colors/ColorConversionTests.cs | 72 ++--- .../ImageProcessor.Tests/Colors/ColorTests.cs | 36 +-- .../Processors/ProcessorTestBase.cs | 4 +- .../Processors/Samplers/SamplerTests.cs | 30 +-- 43 files changed, 563 insertions(+), 1184 deletions(-) delete mode 100644 src/ImageProcessor/ApiPortabilityAnalysis.htm create mode 100644 src/ImageProcessor/Colors/Color.cs delete mode 100644 src/ImageProcessor/Colors/ColorVector.cs rename src/ImageProcessor/Colors/{Bgra.cs => Formats/Bgra32.cs} (71%) rename src/ImageProcessor/Colors/{ => Formats}/Cmyk.cs (98%) rename src/ImageProcessor/Colors/{ => Formats}/Hsv.cs (98%) rename src/ImageProcessor/Colors/{ => Formats}/YCbCr.cs (97%) delete mode 100644 src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs delete mode 100644 src/ImageProcessor/Samplers/Resize - Copy.cs diff --git a/src/ImageProcessor/ApiPortabilityAnalysis.htm b/src/ImageProcessor/ApiPortabilityAnalysis.htm deleted file mode 100644 index 36a7dc2de..000000000 --- a/src/ImageProcessor/ApiPortabilityAnalysis.htm +++ /dev/null @@ -1,218 +0,0 @@ - - - - .NET Portability Report - - -

- .NET Portability Report -

-

- Summary -

- - - - - - - - -
Assembly.NET Core 5.0.NET Framework 4.6.1.NET Native 1.0ASP.NET 5 1.0Mono 3.3.0.0Windows 8.1Windows Phone 8.1
ImageProcessor100%99.7%100%100%97.6%97.9%97.9%
-
-

- ImageProcessor -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Target type.NET Core 5.0.NET Framework 4.6.1.NET Native 1.0ASP.NET 5 1.0Mono 3.3.0.0Windows 8.1Windows Phone 8.1Recommended changes
System.Reflection.TypeInfo
get_Assembly
         
System.Numerics.Vector4
X
Z
Y
W
#ctor(System.Single,System.Single,System.Single,System.Single)
         
System.Array
Empty``1
         
Back to summary -
\ No newline at end of file diff --git a/src/ImageProcessor/Colors/Color.cs b/src/ImageProcessor/Colors/Color.cs new file mode 100644 index 000000000..3f2d27d3b --- /dev/null +++ b/src/ImageProcessor/Colors/Color.cs @@ -0,0 +1,249 @@ +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor +{ + using System.Numerics; + + /// + /// Represents a four-component color using red, green, blue, and alpha data. + /// + /// + /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, + /// as it avoids the need to create new values for modification operations. + /// + public struct Color + { + /// + /// The backing vector for SIMD support. + /// + private Vector4 backingVector; + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The red component of this . + /// + /// + /// The green component of this . + /// + /// + /// The blue component of this . + /// + /// + /// The alpha component of this . + /// + public Color(float r, float g, float b, float a) + : this() + { + this.backingVector.X = r; + this.backingVector.Y = g; + this.backingVector.Z = b; + this.backingVector.W = a; + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The vector. + /// + private Color(Vector4 vector) + { + this.backingVector = vector; + } + + /// + /// Gets or sets the blue component of the color. + /// + public float B + { + get + { + return this.backingVector.X; + } + + set + { + this.backingVector.X = value; + } + } + + /// + /// Gets or sets the green component of the color. + /// + public float G + { + get + { + return this.backingVector.Y; + } + + set + { + this.backingVector.Y = value; + } + } + + /// + /// Gets or sets the red component of the color. + /// + public float R + { + get + { + return this.backingVector.Z; + } + + set + { + this.backingVector.Z = value; + } + } + + /// + /// Gets or sets the alpha component of the color. + /// + public float A + { + get + { + return this.backingVector.W; + } + + set + { + this.backingVector.W = value; + } + } + + /// + /// Gets this color with the component values clamped from 0 to 1. + /// + public Color Limited + { + get + { + float r = this.R.Clamp(0, 1); + float g = this.G.Clamp(0, 1); + float b = this.B.Clamp(0, 1); + float a = this.A.Clamp(0, 1); + return new Color(r, g, b, a); + } + } + + /// + /// Allows the implicit conversion of an instance of to a + /// . + /// + /// + /// The instance of to convert. + /// + /// + /// An instance of . + /// + public static implicit operator Color(Bgra32 color) + { + return new Color(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); + } + + /// + /// Computes the product of multiplying a color by a given factor. + /// + /// The color. + /// The multiplication factor. + /// + /// The + /// + public static Color operator *(Color color, float factor) + { + return new Color(color.backingVector * factor); + } + + /// + /// Computes the product of multiplying a color by a given factor. + /// + /// The multiplication factor. + /// The color. + /// + /// The + /// + public static Color operator *(float factor, Color color) + { + return new Color(color.backingVector * factor); + } + + /// + /// Computes the product of multiplying two colors. + /// + /// The color on the left hand of the operand. + /// The color on the right hand of the operand. + /// + /// The + /// + public static Color operator *(Color left, Color right) + { + return new Color(left.backingVector * right.backingVector); + } + + /// + /// Computes the sum of adding two colors. + /// + /// The color on the left hand of the operand. + /// The color on the right hand of the operand. + /// + /// The + /// + public static Color operator +(Color left, Color right) + { + return new Color(left.R + right.R, left.G + right.G, left.B + right.B, left.A + right.A); + } + + /// + /// Computes the difference left by subtracting one color from another. + /// + /// The color on the left hand of the operand. + /// The color on the right hand of the operand. + /// + /// The + /// + public static Color operator -(Color left, Color right) + { + return new Color(left.R - right.R, left.G - right.G, left.B - right.B, left.A - right.A); + } + + /// + /// Returns a new color whose components are the average of the components of first and second. + /// + /// The first color. + /// The second color. + /// + /// The + /// + public static Color Average(Color first, Color second) + { + return new Color((first.backingVector + second.backingVector) * .5f); + } + + /// + /// Linearly interpolates from one color to another based on the given amount. + /// + /// The first color value. + /// The second color value. + /// + /// The weight value. At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + /// + /// The + /// + public static Color Lerp(Color from, Color to, float amount) + { + amount = amount.Clamp(0f, 1f); + + return (from * (1 - amount)) + (to * amount); + } + } +} diff --git a/src/ImageProcessor/Colors/ColorVector.cs b/src/ImageProcessor/Colors/ColorVector.cs deleted file mode 100644 index 6e253f2d6..000000000 --- a/src/ImageProcessor/Colors/ColorVector.cs +++ /dev/null @@ -1,132 +0,0 @@ -// -// Copyright (c) James South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageProcessor -{ - using System.Numerics; - - public struct ColorVector - { - /// - /// The backing vector for SIMD support. - /// - private Vector4 backingVector; - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The blue component of this . - /// - /// - /// The green component of this . - /// - /// - /// The red component of this . - /// - /// - /// The alpha component of this . - /// - public ColorVector(double b, double g, double r, double a) - : this((float)b, (float)g, (float)r, (float)a) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The blue component of this . - /// - /// - /// The green component of this . - /// - /// - /// The red component of this . - /// - /// - /// The alpha component of this . - /// - public ColorVector(float b, float g, float r, float a) - : this() - { - this.backingVector.X = b; - this.backingVector.Y = g; - this.backingVector.Z = r; - this.backingVector.W = a; - } - - /// The color's blue component, between 0.0 and 1.0 - public float B - { - get - { - return this.backingVector.X; - } - - set - { - this.backingVector.X = value; - } - } - - /// The color's green component, between 0.0 and 1.0 - public float G - { - get - { - return this.backingVector.Y; - } - - set - { - this.backingVector.Y = value; - } - } - - /// The color's red component, between 0.0 and 1.0 - public float R - { - get - { - return this.backingVector.Z; - } - - set - { - this.backingVector.Z = value; - } - } - - /// The color's alpha component, between 0.0 and 1.0 - public float A - { - get - { - return this.backingVector.W; - } - - set - { - this.backingVector.W = value; - } - } - - /// - /// Allows the implicit conversion of an instance of to a - /// . - /// - /// - /// The instance of to convert. - /// - /// - /// An instance of . - /// - public static implicit operator ColorVector(Bgra color) - { - return new ColorVector(color.B / 255f, color.G / 255f, color.R / 255f, color.A / 255f); - } - } -} diff --git a/src/ImageProcessor/Colors/Bgra.cs b/src/ImageProcessor/Colors/Formats/Bgra32.cs similarity index 71% rename from src/ImageProcessor/Colors/Bgra.cs rename to src/ImageProcessor/Colors/Formats/Bgra32.cs index 25b703f6f..9fef962f4 100644 --- a/src/ImageProcessor/Colors/Bgra.cs +++ b/src/ImageProcessor/Colors/Formats/Bgra32.cs @@ -12,32 +12,28 @@ namespace ImageProcessor /// /// Represents an BGRA (blue, green, red, alpha) color. /// - /// - /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, - /// as it avoids the need to create new values for modification operations. - /// [StructLayout(LayoutKind.Explicit)] - public struct Bgra : IEquatable + public struct Bgra32 : IEquatable { /// - /// Represents a that has B, G, R, and A values set to zero. + /// Represents a that has B, G, R, and A values set to zero. /// - public static readonly Bgra Empty = default(Bgra); + public static readonly Bgra32 Empty = default(Bgra32); /// - /// Represents a transparent that has B, G, R, and A values set to 255, 255, 255, 0. + /// Represents a transparent that has B, G, R, and A values set to 255, 255, 255, 0. /// - public static readonly Bgra Transparent = new Bgra(255, 255, 255, 0); + public static readonly Bgra32 Transparent = new Bgra32(255, 255, 255, 0); /// - /// Represents a black that has B, G, R, and A values set to 0, 0, 0, 0. + /// Represents a black that has B, G, R, and A values set to 0, 0, 0, 0. /// - public static readonly Bgra Black = new Bgra(0, 0, 0, 255); + public static readonly Bgra32 Black = new Bgra32(0, 0, 0, 255); /// - /// Represents a white that has B, G, R, and A values set to 255, 255, 255, 255. + /// Represents a white that has B, G, R, and A values set to 255, 255, 255, 255. /// - public static readonly Bgra White = new Bgra(255, 255, 255, 255); + public static readonly Bgra32 White = new Bgra32(255, 255, 255, 255); /// /// Holds the blue component of the color @@ -64,7 +60,7 @@ namespace ImageProcessor public readonly byte A; /// - /// Permits the to be treated as a 32 bit integer. + /// Permits the to be treated as a 32 bit integer. /// [FieldOffset(0)] public readonly int BGRA; @@ -75,18 +71,18 @@ namespace ImageProcessor private const float Epsilon = 0.0001f; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// - /// The blue component of this . + /// The blue component of this . /// /// - /// The green component of this . + /// The green component of this . /// /// - /// The red component of this . + /// The red component of this . /// - public Bgra(byte b, byte g, byte r) + public Bgra32(byte b, byte g, byte r) : this() { this.B = b; @@ -96,21 +92,21 @@ namespace ImageProcessor } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// - /// The blue component of this . + /// The blue component of this . /// /// - /// The green component of this . + /// The green component of this . /// /// - /// The red component of this . + /// The red component of this . /// /// - /// The alpha component of this . + /// The alpha component of this . /// - public Bgra(byte b, byte g, byte r, byte a) + public Bgra32(byte b, byte g, byte r, byte a) : this() { this.B = b; @@ -120,25 +116,25 @@ namespace ImageProcessor } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// /// The combined color components. /// - public Bgra(int bgra) + public Bgra32(int bgra) : this() { this.BGRA = bgra; } /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// /// The hexadecimal representation of the combined color components arranged /// in rgb, rrggbb, or aarrggbb format to match web syntax. /// - public Bgra(string hex) + public Bgra32(string hex) : this() { // Hexadecimal representations are layed out AARRGGBB to we need to do some reordering. @@ -177,37 +173,38 @@ namespace ImageProcessor } /// - /// Gets a value indicating whether this is empty. + /// Gets a value indicating whether this is empty. /// [EditorBrowsable(EditorBrowsableState.Never)] public bool IsEmpty => this.B == 0 && this.G == 0 && this.R == 0 && this.A == 0; /// - /// Allows the implicit conversion of an instance of to a - /// . + /// Allows the implicit conversion of an instance of to a + /// . /// /// - /// The instance of to convert. + /// The instance of to convert. /// /// - /// An instance of . + /// An instance of . /// - public static implicit operator Bgra(ColorVector color) + public static implicit operator Bgra32(Color color) { - return new Bgra((255f * color.B).ToByte(), (255f * color.G).ToByte(), (255f * color.R).ToByte(), (255f * color.A).ToByte()); + color = color.Limited; + return new Bgra32((255f * color.B).ToByte(), (255f * color.G).ToByte(), (255f * color.R).ToByte(), (255f * color.A).ToByte()); } /// /// Allows the implicit conversion of an instance of to a - /// . + /// . /// /// /// The instance of to convert. /// /// - /// An instance of . + /// An instance of . /// - public static implicit operator Bgra(Hsv color) + public static implicit operator Bgra32(Hsv color) { float s = color.S / 100; float v = color.V / 100; @@ -215,7 +212,7 @@ namespace ImageProcessor if (Math.Abs(s) < Epsilon) { byte component = (byte)(v * 255); - return new Bgra(component, component, component, 255); + return new Bgra32(component, component, component, 255); } float h = (Math.Abs(color.H - 360) < Epsilon) ? 0 : color.H / 60; @@ -266,20 +263,20 @@ namespace ImageProcessor break; } - return new Bgra((byte)Math.Round(b * 255), (byte)Math.Round(g * 255), (byte)Math.Round(r * 255)); + return new Bgra32((byte)Math.Round(b * 255), (byte)Math.Round(g * 255), (byte)Math.Round(r * 255)); } /// /// Allows the implicit conversion of an instance of to a - /// . + /// . /// /// /// The instance of to convert. /// /// - /// An instance of . + /// An instance of . /// - public static implicit operator Bgra(YCbCr color) + public static implicit operator Bgra32(YCbCr color) { float y = color.Y; float cb = color.Cb - 128; @@ -289,61 +286,61 @@ namespace ImageProcessor byte g = (y - (0.34414 * cb) - (0.71414 * cr)).ToByte(); byte r = (y + (1.402 * cr)).ToByte(); - return new Bgra(b, g, r, 255); + return new Bgra32(b, g, r, 255); } /// /// Allows the implicit conversion of an instance of to a - /// . + /// . /// /// /// The instance of to convert. /// /// - /// An instance of . + /// An instance of . /// - public static implicit operator Bgra(Cmyk cmykColor) + public static implicit operator Bgra32(Cmyk cmykColor) { int red = Convert.ToInt32((1 - (cmykColor.C / 100)) * (1 - (cmykColor.K / 100)) * 255.0); int green = Convert.ToInt32((1 - (cmykColor.M / 100)) * (1 - (cmykColor.K / 100)) * 255.0); int blue = Convert.ToInt32((1 - (cmykColor.Y / 100)) * (1 - (cmykColor.K / 100)) * 255.0); - return new Bgra(blue.ToByte(), green.ToByte(), red.ToByte()); + return new Bgra32(blue.ToByte(), green.ToByte(), red.ToByte()); } /// - /// Compares two objects. The result specifies whether the values - /// of the , , , and - /// properties of the two objects are equal. + /// Compares two objects. The result specifies whether the values + /// of the , , , and + /// properties of the two objects are equal. /// /// - /// The on the left side of the operand. + /// The on the left side of the operand. /// /// - /// The on the right side of the operand. + /// The on the right side of the operand. /// /// /// True if the current left is equal to the parameter; otherwise, false. /// - public static bool operator ==(Bgra left, Bgra right) + public static bool operator ==(Bgra32 left, Bgra32 right) { return left.Equals(right); } /// - /// Compares two objects. The result specifies whether the values - /// of the , , , and - /// properties of the two objects are unequal. + /// Compares two objects. The result specifies whether the values + /// of the , , , and + /// properties of the two objects are unequal. /// /// - /// The on the left side of the operand. + /// The on the left side of the operand. /// /// - /// The on the right side of the operand. + /// The on the right side of the operand. /// /// /// True if the current left is unequal to the parameter; otherwise, false. /// - public static bool operator !=(Bgra left, Bgra right) + public static bool operator !=(Bgra32 left, Bgra32 right) { return !left.Equals(right); } @@ -357,9 +354,9 @@ namespace ImageProcessor /// Another object to compare to. public override bool Equals(object obj) { - if (obj is Bgra) + if (obj is Bgra32) { - Bgra color = (Bgra)obj; + Bgra32 color = (Bgra32)obj; return this.BGRA == color.BGRA; } @@ -408,7 +405,7 @@ namespace ImageProcessor /// True if the current object is equal to the parameter; otherwise, false. /// /// An object to compare with this object. - public bool Equals(Bgra other) + public bool Equals(Bgra32 other) { return this.BGRA == other.BGRA; } diff --git a/src/ImageProcessor/Colors/Cmyk.cs b/src/ImageProcessor/Colors/Formats/Cmyk.cs similarity index 98% rename from src/ImageProcessor/Colors/Cmyk.cs rename to src/ImageProcessor/Colors/Formats/Cmyk.cs index a11fffdd5..377d35ecc 100644 --- a/src/ImageProcessor/Colors/Cmyk.cs +++ b/src/ImageProcessor/Colors/Formats/Cmyk.cs @@ -72,16 +72,16 @@ namespace ImageProcessor && Math.Abs(this.K) < Epsilon; /// - /// Allows the implicit conversion of an instance of to a + /// Allows the implicit conversion of an instance of to a /// . /// /// - /// The instance of to convert. + /// The instance of to convert. /// /// /// An instance of . /// - public static implicit operator Cmyk(Bgra color) + public static implicit operator Cmyk(Bgra32 color) { float c = (255f - color.R) / 255; float m = (255f - color.G) / 255; diff --git a/src/ImageProcessor/Colors/Hsv.cs b/src/ImageProcessor/Colors/Formats/Hsv.cs similarity index 98% rename from src/ImageProcessor/Colors/Hsv.cs rename to src/ImageProcessor/Colors/Formats/Hsv.cs index 2e184b7e1..942ab8fb7 100644 --- a/src/ImageProcessor/Colors/Hsv.cs +++ b/src/ImageProcessor/Colors/Formats/Hsv.cs @@ -63,16 +63,16 @@ namespace ImageProcessor && Math.Abs(this.V) < Epsilon; /// - /// Allows the implicit conversion of an instance of to a + /// Allows the implicit conversion of an instance of to a /// . /// /// - /// The instance of to convert. + /// The instance of to convert. /// /// /// An instance of . /// - public static implicit operator Hsv(Bgra color) + public static implicit operator Hsv(Bgra32 color) { float r = color.R / 255f; float g = color.G / 255f; diff --git a/src/ImageProcessor/Colors/YCbCr.cs b/src/ImageProcessor/Colors/Formats/YCbCr.cs similarity index 97% rename from src/ImageProcessor/Colors/YCbCr.cs rename to src/ImageProcessor/Colors/Formats/YCbCr.cs index c99fe55fb..a0c9a339b 100644 --- a/src/ImageProcessor/Colors/YCbCr.cs +++ b/src/ImageProcessor/Colors/Formats/YCbCr.cs @@ -65,16 +65,16 @@ namespace ImageProcessor && Math.Abs(this.Cr) < Epsilon; /// - /// Allows the implicit conversion of an instance of to a + /// Allows the implicit conversion of an instance of to a /// . /// /// - /// The instance of to convert. + /// The instance of to convert. /// /// /// An instance of . /// - public static implicit operator YCbCr(Bgra color) + public static implicit operator YCbCr(Bgra32 color) { byte b = color.B; byte g = color.G; diff --git a/src/ImageProcessor/Common/Helpers/ImageMaths.cs b/src/ImageProcessor/Common/Helpers/ImageMaths.cs index 71f7d9670..b2bf0dede 100644 --- a/src/ImageProcessor/Common/Helpers/ImageMaths.cs +++ b/src/ImageProcessor/Common/Helpers/ImageMaths.cs @@ -12,6 +12,12 @@ namespace ImageProcessor /// internal static class ImageMaths { + /// + /// Represents PI, the ratio of a circle's circumference to its diameter. + /// + // ReSharper disable once InconsistentNaming + public const float PI = 3.1415926535897931f; + /// /// Returns the result of a B-C filter against the given value. /// @@ -20,11 +26,11 @@ namespace ImageProcessor /// The B-Spline curve variable. /// The Cardinal curve variable. /// - /// The . + /// The . /// - public static double GetBcValue(double x, double b, double c) + public static float GetBcValue(float x, float b, float c) { - double temp; + float temp; if (x < 0) { @@ -54,19 +60,19 @@ namespace ImageProcessor /// The value to calculate the result for. /// /// - /// The . + /// The . /// - public static double SinC(double x) + public static float SinC(float x) { - const double Epsilon = .0001; + const float Epsilon = .00001f; if (Math.Abs(x) > Epsilon) { - x *= Math.PI; - return Clean(Math.Sin(x) / x); + x *= PI; + return Clean((float)Math.Sin(x) / x); } - return 1.0; + return 1.0f; } /// @@ -74,15 +80,15 @@ namespace ImageProcessor /// /// The value to clean. /// - /// The + /// The /// . - private static double Clean(double x) + private static float Clean(float x) { - const double Epsilon = .0001; + const float Epsilon = .00001f; if (Math.Abs(x) < Epsilon) { - return 0.0; + return 0f; } return x; diff --git a/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs b/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs deleted file mode 100644 index a876b45ef..000000000 --- a/src/ImageProcessor/Common/Helpers/PixelOperations - Copy.cs +++ /dev/null @@ -1,193 +0,0 @@ -// -// Copyright (c) James South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageProcessor -{ - using System; - - /// - /// Performs per-pixel operations. - /// - public static class PixelOperations - { - /// - /// The array of bytes representing each possible value of color component - /// converted from sRGB to the linear color space. - /// - private static readonly Lazy LinearBytes = new Lazy(GetLinearBytes); - - /// - /// The array of bytes representing each possible value of color component - /// converted from linear to the sRGB color space. - /// - private static readonly Lazy SrgbBytes = new Lazy(GetSrgbBytes); - - /// - /// The array of bytes representing each possible value of color component - /// converted from gamma to the linear color space. - /// - private static readonly Lazy LinearGammaBytes = new Lazy(GetLinearGammaBytes); - - /// - /// The array of bytes representing each possible value of color component - /// converted from linear to the gamma color space. - /// - private static readonly Lazy GammaLinearBytes = new Lazy(GetGammaLinearBytes); - - /// - /// Converts an pixel from an sRGB color-space to the equivalent linear color-space. - /// - /// - /// The to convert. - /// - /// - /// The . - /// - public static Bgra ToLinear(Bgra composite) - { - // Create only once and lazily. - // byte[] ramp = LinearGammaBytes.Value; - byte[] ramp = LinearBytes.Value; - - return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A); - } - - /// - /// Converts a pixel from a linear color-space to the equivalent sRGB color-space. - /// - /// - /// The to convert. - /// - /// - /// The . - /// - public static Bgra ToSrgb(Bgra linear) - { - // Create only once and lazily. - // byte[] ramp = GammaLinearBytes.Value; - byte[] ramp = SrgbBytes.Value; - - return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A); - } - - /// - /// Gets an array of bytes representing each possible value of color component - /// converted from sRGB to the linear color space. - /// - /// - /// The . - /// - private static byte[] GetLinearBytes() - { - byte[] ramp = new byte[256]; - for (int x = 0; x < 256; ++x) - { - byte val = (255f * SrgbToLinear(x / 255f)).ToByte(); - ramp[x] = val; - } - - return ramp; - } - - /// - /// Gets an array of bytes representing each possible value of color component - /// converted from linear to the sRGB color space. - /// - /// - /// The . - /// - private static byte[] GetSrgbBytes() - { - byte[] ramp = new byte[256]; - for (int x = 0; x < 256; ++x) - { - byte val = (255f * LinearToSrgb(x / 255f)).ToByte(); - ramp[x] = val; - } - - return ramp; - } - - /// - /// Gets the correct linear value from an sRGB signal. - /// - /// - /// - /// The signal value to convert. - /// - /// The . - /// - private static float SrgbToLinear(float signal) - { - float a = 0.055f; - - if (signal <= 0.04045) - { - return signal / 12.92f; - } - - return (float)Math.Pow((signal + a) / (1 + a), 2.4); - } - - /// - /// Gets the correct sRGB value from an linear signal. - /// - /// - /// - /// The signal value to convert. - /// - /// The . - /// - private static float LinearToSrgb(float signal) - { - float a = 0.055f; - - if (signal <= 0.0031308) - { - return signal * 12.92f; - } - - return ((float)((1 + a) * Math.Pow(signal, 1 / 2.4f))) - a; - } - - /// - /// Gets an array of bytes representing each possible value of color component - /// converted from gamma to the linear color space. - /// - /// - /// The . - /// - private static byte[] GetLinearGammaBytes() - { - byte[] ramp = new byte[256]; - for (int x = 0; x < 256; ++x) - { - byte val = (255f * Math.Pow(x / 255f, 2.2)).ToByte(); - ramp[x] = val; - } - - return ramp; - } - - /// - /// Gets an array of bytes representing each possible value of color component - /// converted from linear to the gamma color space. - /// - /// - /// The . - /// - private static byte[] GetGammaLinearBytes() - { - byte[] ramp = new byte[256]; - for (int x = 0; x < 256; ++x) - { - byte val = (255f * Math.Pow(x / 255f, 1 / 2.2)).ToByte(); - ramp[x] = val; - } - - return ramp; - } - } -} \ No newline at end of file diff --git a/src/ImageProcessor/Common/Helpers/PixelOperations.cs b/src/ImageProcessor/Common/Helpers/PixelOperations.cs index 0a9c43797..048b2e6b2 100644 --- a/src/ImageProcessor/Common/Helpers/PixelOperations.cs +++ b/src/ImageProcessor/Common/Helpers/PixelOperations.cs @@ -6,110 +6,49 @@ namespace ImageProcessor { using System; + using System.Collections.Concurrent; /// /// Performs per-pixel operations. /// public static class PixelOperations { - /// - /// The array of values representing each possible value of color component - /// converted from sRGB to the linear color space. - /// - private static readonly Lazy LinearLut = new Lazy(GetLinearBytes); - - /// - /// The array of values representing each possible value of color component - /// converted from linear to the sRGB color space. - /// - private static readonly Lazy SrgbLut = new Lazy(GetSrgbBytes); - - /// - /// The array of bytes representing each possible value of color component - /// converted from gamma to the linear color space. - /// - private static readonly Lazy LinearGammaBytes = new Lazy(GetLinearGammaBytes); - - /// - /// The array of bytes representing each possible value of color component - /// converted from linear to the gamma color space. - /// - private static readonly Lazy GammaLinearBytes = new Lazy(GetGammaLinearBytes); - /// /// Converts an pixel from an sRGB color-space to the equivalent linear color-space. /// /// - /// The to convert. + /// The to convert. /// /// - /// The . + /// The . /// - public static Bgra ToLinear(ColorVector composite) + public static Color ToLinear(Color composite) { - // Create only once and lazily. - // byte[] ramp = LinearGammaBytes.Value; - float[] ramp = LinearLut.Value; + // TODO: Figure out a way to either cache these values quickly or perform the calcuations together. + composite.R = SrgbToLinear(composite.R); + composite.G = SrgbToLinear(composite.G); + composite.B = SrgbToLinear(composite.B); - // TODO: This just doesn't seem right to me. - return new ColorVector(ramp[(composite.B * 255).ToByte()], ramp[(composite.G * 255).ToByte()], ramp[(composite.R * 255).ToByte()], composite.A); + return composite; } /// /// Converts a pixel from a linear color-space to the equivalent sRGB color-space. /// /// - /// The to convert. + /// The to convert. /// /// - /// The . - /// - public static Bgra ToSrgb(ColorVector linear) - { - // Create only once and lazily. - // byte[] ramp = GammaLinearBytes.Value; - float[] ramp = SrgbLut.Value; - - // TODO: This just doesn't seem right to me. - return new ColorVector(ramp[(linear.B * 255).ToByte()], ramp[(linear.G * 255).ToByte()], (linear.R * 255).ToByte(), linear.A); - } - - /// - /// Gets an array of bytes representing each possible value of color component - /// converted from sRGB to the linear color space. - /// - /// - /// The . - /// - private static float[] GetLinearBytes() - { - float[] ramp = new float[256]; - for (int x = 0; x < 256; ++x) - { - float val = SrgbToLinear(x / 255f); - ramp[x] = val; - } - - return ramp; - } - - /// - /// Gets an array of bytes representing each possible value of color component - /// converted from linear to the sRGB color space. - /// - /// - /// The . + /// The . /// - private static float[] GetSrgbBytes() + public static Color ToSrgb(Color linear) { - float[] ramp = new float[256]; - for (int x = 0; x < 256; ++x) - { - float val = LinearToSrgb(x / 255f); - ramp[x] = val; - } + // TODO: Figure out a way to either cache these values quickly or perform the calcuations together. + linear.R = LinearToSrgb(linear.R); + linear.G = LinearToSrgb(linear.G); + linear.B = LinearToSrgb(linear.B); - return ramp; + return linear; } /// @@ -123,14 +62,12 @@ namespace ImageProcessor /// private static float SrgbToLinear(float signal) { - float a = 0.055f; - - if (signal <= 0.04045) + if (signal <= 0.04045f) { return signal / 12.92f; } - return (float)Math.Pow((signal + a) / (1 + a), 2.4); + return (float)Math.Pow((signal + 0.055f) / 1.055f, 2.4f); } /// @@ -144,52 +81,12 @@ namespace ImageProcessor /// private static float LinearToSrgb(float signal) { - float a = 0.055f; - - if (signal <= 0.0031308) + if (signal <= 0.0031308f) { return signal * 12.92f; } - return ((float)((1 + a) * Math.Pow(signal, 1 / 2.4f))) - a; - } - - /// - /// Gets an array of bytes representing each possible value of color component - /// converted from gamma to the linear color space. - /// - /// - /// The . - /// - private static byte[] GetLinearGammaBytes() - { - byte[] ramp = new byte[256]; - for (int x = 0; x < 256; ++x) - { - byte val = (255f * Math.Pow(x / 255f, 2.2)).ToByte(); - ramp[x] = val; - } - - return ramp; - } - - /// - /// Gets an array of bytes representing each possible value of color component - /// converted from linear to the gamma color space. - /// - /// - /// The . - /// - private static byte[] GetGammaLinearBytes() - { - byte[] ramp = new byte[256]; - for (int x = 0; x < 256; ++x) - { - byte val = (255f * Math.Pow(x / 255f, 1 / 2.2)).ToByte(); - ramp[x] = val; - } - - return ramp; + return (1.055f * (float)Math.Pow(signal, 0.41666666f)) - 0.055f; } } } \ No newline at end of file diff --git a/src/ImageProcessor/Filters/Alpha.cs b/src/ImageProcessor/Filters/Alpha.cs index 2f410525a..02c7ff364 100644 --- a/src/ImageProcessor/Filters/Alpha.cs +++ b/src/ImageProcessor/Filters/Alpha.cs @@ -49,9 +49,9 @@ namespace ImageProcessor.Filters { for (int x = startX; x < endX; x++) { - Bgra color = source[x, y]; + Bgra32 color = source[x, y]; double a = color.A * alpha; - target[x, y] = new Bgra(color.B, color.G, color.R, a.ToByte()); + target[x, y] = new Bgra32(color.B, color.G, color.R, a.ToByte()); } } }); diff --git a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs index 7f42669bd..68f929be6 100644 --- a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs +++ b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs @@ -41,8 +41,8 @@ namespace ImageProcessor.Filters int startX = sourceRectangle.X; int endX = sourceRectangle.Right; ColorMatrix matrix = this.Value; - Bgra previousColor = source[0, 0]; - Bgra pixelValue = this.ApplyMatrix(previousColor, matrix); + Bgra32 previousColor = source[0, 0]; + Bgra32 pixelValue = this.ApplyMatrix(previousColor, matrix); Parallel.For( startY, @@ -53,7 +53,7 @@ namespace ImageProcessor.Filters { for (int x = startX; x < endX; x++) { - Bgra sourceColor = source[x, y]; + Bgra32 sourceColor = source[x, y]; // Check if this is the same as the last pixel. If so use that value // rather than calculating it again. This is an inexpensive optimization. @@ -78,9 +78,9 @@ namespace ImageProcessor.Filters /// The source color. /// The matrix. /// - /// The . + /// The . /// - private Bgra ApplyMatrix(Bgra sourceColor, ColorMatrix matrix) + private Bgra32 ApplyMatrix(Bgra32 sourceColor, ColorMatrix matrix) { bool gamma = this.GammaAdjust; @@ -100,7 +100,8 @@ namespace ImageProcessor.Filters byte b = ((sr * matrix.Matrix02) + (sg * matrix.Matrix12) + (sb * matrix.Matrix22) + (sa * matrix.Matrix32) + (255f * matrix.Matrix42)).ToByte(); byte a = ((sr * matrix.Matrix03) + (sg * matrix.Matrix13) + (sb * matrix.Matrix23) + (sa * matrix.Matrix33) + (255f * matrix.Matrix43)).ToByte(); - return gamma ? PixelOperations.ToSrgb(new Bgra(b, g, r, a)) : new Bgra(b, g, r, a); + // TODO: Fix this. + return gamma ? (Bgra32)PixelOperations.ToSrgb(new Bgra32(b, g, r, a)) : new Bgra32(b, g, r, a); } } } diff --git a/src/ImageProcessor/Filters/Contrast.cs b/src/ImageProcessor/Filters/Contrast.cs index c5abb79f6..2644b8f72 100644 --- a/src/ImageProcessor/Filters/Contrast.cs +++ b/src/ImageProcessor/Filters/Contrast.cs @@ -49,7 +49,7 @@ namespace ImageProcessor.Filters { for (int x = startX; x < endX; x++) { - Bgra sourceColor = source[x, y]; + Bgra32 sourceColor = source[x, y]; sourceColor = PixelOperations.ToLinear(sourceColor); double r = sourceColor.R / 255.0; @@ -73,7 +73,7 @@ namespace ImageProcessor.Filters b *= 255; b = b.ToByte(); - Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), sourceColor.A); + Bgra32 destinationColor = new Bgra32(b.ToByte(), g.ToByte(), r.ToByte(), sourceColor.A); destinationColor = PixelOperations.ToSrgb(destinationColor); target[x, y] = destinationColor; } diff --git a/src/ImageProcessor/Filters/Invert.cs b/src/ImageProcessor/Filters/Invert.cs index 241835fd1..ade3c6829 100644 --- a/src/ImageProcessor/Filters/Invert.cs +++ b/src/ImageProcessor/Filters/Invert.cs @@ -30,8 +30,8 @@ namespace ImageProcessor.Filters for (int x = startX; x < endX; x++) { // TODO: This doesn't work for gamma test images. - Bgra color = source[x, y]; - Bgra targetColor = new Bgra((255 - color.B).ToByte(), (255 - color.G).ToByte(), (255 - color.R).ToByte(), color.A); + Bgra32 color = source[x, y]; + Bgra32 targetColor = new Bgra32((255 - color.B).ToByte(), (255 - color.G).ToByte(), (255 - color.R).ToByte(), color.A); target[x, y] = targetColor; } } diff --git a/src/ImageProcessor/Formats/Gif/GifEncoder.cs b/src/ImageProcessor/Formats/Gif/GifEncoder.cs index cf8dc73d0..735d26c39 100644 --- a/src/ImageProcessor/Formats/Gif/GifEncoder.cs +++ b/src/ImageProcessor/Formats/Gif/GifEncoder.cs @@ -127,7 +127,7 @@ namespace ImageProcessor.Formats QuantizedImage quantizedImage = quantizer.Quantize(image); // Grab the pallete and write it to the stream. - Bgra[] pallete = quantizedImage.Palette; + Bgra32[] pallete = quantizedImage.Palette; int pixelCount = pallete.Length; // Get max colors for bit depth. @@ -137,7 +137,7 @@ namespace ImageProcessor.Formats for (int i = 0; i < pixelCount; i++) { int offset = i * 3; - Bgra color = pallete[i]; + Bgra32 color = pallete[i]; colorTable[offset + 2] = color.B; colorTable[offset + 1] = color.G; colorTable[offset + 0] = color.R; diff --git a/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs b/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs index 7358d015a..1b08f16d7 100644 --- a/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs +++ b/src/ImageProcessor/Formats/Gif/Quantizer/OctreeQuantizer.cs @@ -70,7 +70,7 @@ namespace ImageProcessor.Formats /// This function need only be overridden if your quantize algorithm needs two passes, /// such as an Octree quantizer. /// - protected override void InitialQuantizePixel(Bgra pixel) + protected override void InitialQuantizePixel(Bgra32 pixel) { // Add the color to the Octree this.octree.AddColor(pixel); @@ -85,7 +85,7 @@ namespace ImageProcessor.Formats /// /// The quantized value /// - protected override byte QuantizePixel(Bgra pixel) + protected override byte QuantizePixel(Bgra32 pixel) { // The color at [maxColors] is set to transparent byte paletteIndex = (byte)this.maxColors; @@ -105,13 +105,13 @@ namespace ImageProcessor.Formats /// /// The new color palette /// - protected override List GetPalette() + protected override List GetPalette() { // First off convert the Octree to maxColors colors - List palette = this.octree.Palletize(Math.Max(this.maxColors - 1, 1)); + List palette = this.octree.Palletize(Math.Max(this.maxColors - 1, 1)); // Add empty color for transparency - palette.Add(Bgra.Empty); + palette.Add(Bgra32.Empty); return palette; } @@ -190,9 +190,9 @@ namespace ImageProcessor.Formats /// Add a given color value to the Octree /// /// - /// The containing color information to add. + /// The containing color information to add. /// - public void AddColor(Bgra pixel) + public void AddColor(Bgra32 pixel) { // Check if this request is for the same color as the last if (this.previousColor == pixel.BGRA) @@ -226,7 +226,7 @@ namespace ImageProcessor.Formats /// /// An with the palletized colors /// - public List Palletize(int colorCount) + public List Palletize(int colorCount) { while (this.Leaves > colorCount) { @@ -234,7 +234,7 @@ namespace ImageProcessor.Formats } // Now palletize the nodes - List palette = new List(this.Leaves); + List palette = new List(this.Leaves); int paletteIndex = 0; this.root.ConstructPalette(palette, ref paletteIndex); @@ -246,12 +246,12 @@ namespace ImageProcessor.Formats /// Get the palette index for the passed color /// /// - /// The containing the pixel data. + /// The containing the pixel data. /// /// /// The index of the given structure. /// - public int GetPaletteIndex(Bgra pixel) + public int GetPaletteIndex(Bgra32 pixel) { return this.root.GetPaletteIndex(pixel, 0); } @@ -387,7 +387,7 @@ namespace ImageProcessor.Formats /// /// The tree to which this node belongs /// - public void AddColor(Bgra pixel, int colorBits, int level, Octree octree) + public void AddColor(Bgra32 pixel, int colorBits, int level, Octree octree) { // Update the color information if this is a leaf if (this.leaf) @@ -458,7 +458,7 @@ namespace ImageProcessor.Formats /// /// The current palette index /// - public void ConstructPalette(List palette, ref int index) + public void ConstructPalette(List palette, ref int index) { if (this.leaf) { @@ -470,7 +470,7 @@ namespace ImageProcessor.Formats byte b = (this.blue / this.pixelCount).ToByte(); // And set the color of the palette entry - palette.Add(new Bgra(b, g, r)); + palette.Add(new Bgra32(b, g, r)); } else { @@ -489,7 +489,7 @@ namespace ImageProcessor.Formats /// Return the palette index for the passed color /// /// - /// The representing the pixel. + /// The representing the pixel. /// /// /// The level. @@ -497,7 +497,7 @@ namespace ImageProcessor.Formats /// /// The representing the index of the pixel in the palette. /// - public int GetPaletteIndex(Bgra pixel, int level) + public int GetPaletteIndex(Bgra32 pixel, int level) { int index = this.paletteIndex; @@ -527,7 +527,7 @@ namespace ImageProcessor.Formats /// /// The pixel to add. /// - public void Increment(Bgra pixel) + public void Increment(Bgra32 pixel) { this.pixelCount++; this.red += pixel.R; diff --git a/src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs b/src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs index 76c273fe8..da55ff020 100644 --- a/src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs +++ b/src/ImageProcessor/Formats/Gif/Quantizer/QuantizedImage.cs @@ -19,7 +19,7 @@ namespace ImageProcessor.Formats /// The image height. /// The color palette. /// The quantized pixels. - public QuantizedImage(int width, int height, Bgra[] palette, byte[] pixels) + public QuantizedImage(int width, int height, Bgra32[] palette, byte[] pixels) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); @@ -51,7 +51,7 @@ namespace ImageProcessor.Formats /// /// Gets the color palette of this . /// - public Bgra[] Palette { get; } + public Bgra32[] Palette { get; } /// /// Gets the pixels of this . @@ -74,7 +74,7 @@ namespace ImageProcessor.Formats for (int i = 0; i < pixelCount; i++) { int offset = i * 4; - Bgra color = this.Palette[this.Pixels[i]]; + Bgra32 color = this.Palette[this.Pixels[i]]; bgraPixels[offset + 0] = color.B; bgraPixels[offset + 1] = color.G; bgraPixels[offset + 2] = color.R; diff --git a/src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs b/src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs index dda33d479..a374ae3b5 100644 --- a/src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs +++ b/src/ImageProcessor/Formats/Gif/Quantizer/Quantizer.cs @@ -56,7 +56,7 @@ namespace ImageProcessor.Formats byte[] quantizedPixels = new byte[width * height]; - List palette = this.GetPalette(); + List palette = this.GetPalette(); this.SecondPass(imageBase, quantizedPixels, width, height); @@ -95,7 +95,7 @@ namespace ImageProcessor.Formats int i = 0; // Convert the first pixel, so that I have values going into the loop - Bgra previousPixel = source[0, 0]; + Bgra32 previousPixel = source[0, 0]; byte pixelValue = this.QuantizePixel(previousPixel); output[0] = pixelValue; @@ -104,7 +104,7 @@ namespace ImageProcessor.Formats { for (int x = 0; x < width; x++) { - Bgra sourcePixel = source[x, y]; + Bgra32 sourcePixel = source[x, y]; // Check if this is the same as the last pixel. If so use that value // rather than calculating it again. This is an inexpensive optimization. @@ -132,7 +132,7 @@ namespace ImageProcessor.Formats /// This function need only be overridden if your quantize algorithm needs two passes, /// such as an Octree quantizer. /// - protected virtual void InitialQuantizePixel(Bgra pixel) + protected virtual void InitialQuantizePixel(Bgra32 pixel) { } @@ -145,7 +145,7 @@ namespace ImageProcessor.Formats /// /// The quantized value /// - protected abstract byte QuantizePixel(Bgra pixel); + protected abstract byte QuantizePixel(Bgra32 pixel); /// /// Retrieve the palette for the quantized image @@ -153,6 +153,6 @@ namespace ImageProcessor.Formats /// /// The new color palette /// - protected abstract List GetPalette(); + protected abstract List GetPalette(); } } \ No newline at end of file diff --git a/src/ImageProcessor/IImageBase.cs b/src/ImageProcessor/IImageBase.cs index 62fc821b3..a4ee9e04f 100644 --- a/src/ImageProcessor/IImageBase.cs +++ b/src/ImageProcessor/IImageBase.cs @@ -66,8 +66,8 @@ namespace ImageProcessor /// The y-coordinate of the pixel. Must be greater /// than zero and smaller than the width of the pixel. /// - /// The at the specified position. - Bgra this[int x, int y] { get; set; } + /// The at the specified position. + Bgra32 this[int x, int y] { get; set; } /// /// Sets the pixel array of the image. diff --git a/src/ImageProcessor/ImageBase.cs b/src/ImageProcessor/ImageBase.cs index 405cd888f..f7c410b82 100644 --- a/src/ImageProcessor/ImageBase.cs +++ b/src/ImageProcessor/ImageBase.cs @@ -130,8 +130,8 @@ namespace ImageProcessor /// The y-coordinate of the pixel. Must be greater /// than zero and smaller than the width of the pixel. /// - /// The at the specified position. - public Bgra this[int x, int y] + /// The at the specified position. + public Bgra32 this[int x, int y] { get { @@ -148,7 +148,7 @@ namespace ImageProcessor #endif int start = ((y * this.Width) + x) * 4; - return new Bgra(this.Pixels[start], this.Pixels[start + 1], this.Pixels[start + 2], this.Pixels[start + 3]); + return new Bgra32(this.Pixels[start], this.Pixels[start + 1], this.Pixels[start + 2], this.Pixels[start + 3]); } set diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 0c53f80f1..6ada545a7 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -41,8 +41,8 @@ 4 - - + + @@ -82,8 +82,8 @@ - - + + @@ -198,7 +198,7 @@ - + @@ -237,7 +237,7 @@ - + diff --git a/src/ImageProcessor/ImageProcessor.csproj.DotSettings b/src/ImageProcessor/ImageProcessor.csproj.DotSettings index 72de168d8..cd6b6487b 100644 --- a/src/ImageProcessor/ImageProcessor.csproj.DotSettings +++ b/src/ImageProcessor/ImageProcessor.csproj.DotSettings @@ -1,6 +1,7 @@  CSharp60 True + True True True True diff --git a/src/ImageProcessor/Samplers/Resamplers/BicubicResampler.cs b/src/ImageProcessor/Samplers/Resamplers/BicubicResampler.cs index 27a6d6742..61dbfbb89 100644 --- a/src/ImageProcessor/Samplers/Resamplers/BicubicResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/BicubicResampler.cs @@ -12,28 +12,28 @@ namespace ImageProcessor.Samplers public class BicubicResampler : IResampler { /// - public double Radius => 2; + public float Radius => 2; /// - public double GetValue(double x) + public float GetValue(float x) { // The coefficient. - double a = -0.5; + float a = -0.5f; if (x < 0) { x = -x; } - double result = 0; + float result = 0; if (x <= 1) { - result = (((1.5 * x) - 2.5) * x * x) + 1; + result = (((1.5f * x) - 2.5f) * x * x) + 1; } else if (x < 2) { - result = (((((a * x) + 2.5) * x) - 4) * x) + 2; + result = (((((a * x) + 2.5f) * x) - 4) * x) + 2; } return result; diff --git a/src/ImageProcessor/Samplers/Resamplers/BoxResampler.cs b/src/ImageProcessor/Samplers/Resamplers/BoxResampler.cs index 49e407934..0a0ec975e 100644 --- a/src/ImageProcessor/Samplers/Resamplers/BoxResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/BoxResampler.cs @@ -11,10 +11,10 @@ namespace ImageProcessor.Samplers public class BoxResampler : IResampler { /// - public double Radius => 0.5; + public float Radius => 0.5f; /// - public double GetValue(double x) + public float GetValue(float x) { if (x < 0) { diff --git a/src/ImageProcessor/Samplers/Resamplers/CatmullRomResampler.cs b/src/ImageProcessor/Samplers/Resamplers/CatmullRomResampler.cs index 4bfcbef9a..d138e3b0c 100644 --- a/src/ImageProcessor/Samplers/Resamplers/CatmullRomResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/CatmullRomResampler.cs @@ -12,13 +12,13 @@ namespace ImageProcessor.Samplers public class CatmullRomResampler : IResampler { /// - public double Radius => 2; + public float Radius => 2; /// - public double GetValue(double x) + public float GetValue(float x) { - const double B = 0; - const double C = 1 / 2d; + const float B = 0; + const float C = 1 / 2f; return ImageMaths.GetBcValue(x, B, C); } diff --git a/src/ImageProcessor/Samplers/Resamplers/HermiteResampler.cs b/src/ImageProcessor/Samplers/Resamplers/HermiteResampler.cs index 1134ebcc7..3857a07da 100644 --- a/src/ImageProcessor/Samplers/Resamplers/HermiteResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/HermiteResampler.cs @@ -12,13 +12,13 @@ namespace ImageProcessor.Samplers public class HermiteResampler : IResampler { /// - public double Radius => 2; + public float Radius => 2; /// - public double GetValue(double x) + public float GetValue(float x) { - const double B = 0; - const double C = 0; + const float B = 0; + const float C = 0; return ImageMaths.GetBcValue(x, B, C); } diff --git a/src/ImageProcessor/Samplers/Resamplers/IResampler.cs b/src/ImageProcessor/Samplers/Resamplers/IResampler.cs index 37ee3c9ca..de71f571a 100644 --- a/src/ImageProcessor/Samplers/Resamplers/IResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/IResampler.cs @@ -1,22 +1,27 @@ -namespace ImageProcessor.Samplers +// +// Copyright (c) James South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessor.Samplers { /// - /// Encasulates an interpolation algorithm for resampling images. + /// Encapsulates an interpolation algorithm for resampling images. /// public interface IResampler { /// /// Gets the radius in which to sample pixels. /// - double Radius { get; } + float Radius { get; } /// /// Gets the result of the interpolation algorithm. /// /// The value to process. /// - /// The + /// The /// - double GetValue(double x); + float GetValue(float x); } } diff --git a/src/ImageProcessor/Samplers/Resamplers/Lanczos3Resampler.cs b/src/ImageProcessor/Samplers/Resamplers/Lanczos3Resampler.cs index f871a9b55..102453a06 100644 --- a/src/ImageProcessor/Samplers/Resamplers/Lanczos3Resampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/Lanczos3Resampler.cs @@ -12,10 +12,10 @@ namespace ImageProcessor.Samplers public class Lanczos3Resampler : IResampler { /// - public double Radius => 3; + public float Radius => 3; /// - public double GetValue(double x) + public float GetValue(float x) { if (x < 0) { diff --git a/src/ImageProcessor/Samplers/Resamplers/Lanczos5Resampler.cs b/src/ImageProcessor/Samplers/Resamplers/Lanczos5Resampler.cs index 43b22a61d..bbf36f686 100644 --- a/src/ImageProcessor/Samplers/Resamplers/Lanczos5Resampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/Lanczos5Resampler.cs @@ -12,10 +12,10 @@ namespace ImageProcessor.Samplers public class Lanczos5Resampler : IResampler { /// - public double Radius => 5; + public float Radius => 5; /// - public double GetValue(double x) + public float GetValue(float x) { if (x < 0) { diff --git a/src/ImageProcessor/Samplers/Resamplers/Lanczos8Resampler.cs b/src/ImageProcessor/Samplers/Resamplers/Lanczos8Resampler.cs index 4493824b5..3ecce56d5 100644 --- a/src/ImageProcessor/Samplers/Resamplers/Lanczos8Resampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/Lanczos8Resampler.cs @@ -12,10 +12,10 @@ namespace ImageProcessor.Samplers public class Lanczos8Resampler : IResampler { /// - public double Radius => 8; + public float Radius => 8; /// - public double GetValue(double x) + public float GetValue(float x) { if (x < 0) { diff --git a/src/ImageProcessor/Samplers/Resamplers/MitchellNetravaliResampler.cs b/src/ImageProcessor/Samplers/Resamplers/MitchellNetravaliResampler.cs index 69e034eea..0254a1cfc 100644 --- a/src/ImageProcessor/Samplers/Resamplers/MitchellNetravaliResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/MitchellNetravaliResampler.cs @@ -12,13 +12,13 @@ namespace ImageProcessor.Samplers public class MitchellNetravaliResampler : IResampler { /// - public double Radius => 2; + public float Radius => 2; /// - public double GetValue(double x) + public float GetValue(float x) { - const double B = 1 / 3d; - const double C = 1 / 3d; + const float B = 1 / 3f; + const float C = 1 / 3f; return ImageMaths.GetBcValue(x, B, C); } diff --git a/src/ImageProcessor/Samplers/Resamplers/RobidouxResampler.cs b/src/ImageProcessor/Samplers/Resamplers/RobidouxResampler.cs index d72c20ee1..959caf3c3 100644 --- a/src/ImageProcessor/Samplers/Resamplers/RobidouxResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/RobidouxResampler.cs @@ -12,13 +12,13 @@ namespace ImageProcessor.Samplers public class RobidouxResampler : IResampler { /// - public double Radius => 2; + public float Radius => 2; /// - public double GetValue(double x) + public float GetValue(float x) { - const double B = 0.3782; - const double C = 0.3109; + const float B = 0.3782f; + const float C = 0.3109f; return ImageMaths.GetBcValue(x, B, C); } diff --git a/src/ImageProcessor/Samplers/Resamplers/RobidouxSharpResampler.cs b/src/ImageProcessor/Samplers/Resamplers/RobidouxSharpResampler.cs index ac8566d5e..4d50a9fd0 100644 --- a/src/ImageProcessor/Samplers/Resamplers/RobidouxSharpResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/RobidouxSharpResampler.cs @@ -12,13 +12,13 @@ namespace ImageProcessor.Samplers public class RobidouxSharpResampler : IResampler { /// - public double Radius => 2; + public float Radius => 2; /// - public double GetValue(double x) + public float GetValue(float x) { - const double B = 0.2620; - const double C = 0.3690; + const float B = 0.2620f; + const float C = 0.3690f; return ImageMaths.GetBcValue(x, B, C); } diff --git a/src/ImageProcessor/Samplers/Resamplers/RobidouxSoftResampler.cs b/src/ImageProcessor/Samplers/Resamplers/RobidouxSoftResampler.cs index de0e536ba..14c84ac93 100644 --- a/src/ImageProcessor/Samplers/Resamplers/RobidouxSoftResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/RobidouxSoftResampler.cs @@ -12,13 +12,13 @@ namespace ImageProcessor.Samplers public class RobidouxSoftResampler : IResampler { /// - public double Radius => 2; + public float Radius => 2; /// - public double GetValue(double x) + public float GetValue(float x) { - const double B = 0.6796; - const double C = 0.1602; + const float B = 0.6796f; + const float C = 0.1602f; return ImageMaths.GetBcValue(x, B, C); } diff --git a/src/ImageProcessor/Samplers/Resamplers/SplineResampler.cs b/src/ImageProcessor/Samplers/Resamplers/SplineResampler.cs index 1449ab01c..db51a5fcd 100644 --- a/src/ImageProcessor/Samplers/Resamplers/SplineResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/SplineResampler.cs @@ -12,13 +12,13 @@ namespace ImageProcessor.Samplers public class SplineResampler : IResampler { /// - public double Radius => 2; + public float Radius => 2; /// - public double GetValue(double x) + public float GetValue(float x) { - const double B = 1; - const double C = 0; + const float B = 1; + const float C = 0; return ImageMaths.GetBcValue(x, B, C); } diff --git a/src/ImageProcessor/Samplers/Resamplers/TriangleResampler.cs b/src/ImageProcessor/Samplers/Resamplers/TriangleResampler.cs index 779b5180e..871fbbdb6 100644 --- a/src/ImageProcessor/Samplers/Resamplers/TriangleResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/TriangleResampler.cs @@ -11,10 +11,10 @@ namespace ImageProcessor.Samplers public class TriangleResampler : IResampler { /// - public double Radius => 1; + public float Radius => 1; /// - public double GetValue(double x) + public float GetValue(float x) { if (x < 0) { diff --git a/src/ImageProcessor/Samplers/Resamplers/WelchResampler.cs b/src/ImageProcessor/Samplers/Resamplers/WelchResampler.cs index d55a1415b..c4ea4f292 100644 --- a/src/ImageProcessor/Samplers/Resamplers/WelchResampler.cs +++ b/src/ImageProcessor/Samplers/Resamplers/WelchResampler.cs @@ -12,10 +12,10 @@ namespace ImageProcessor.Samplers public class WelchResampler : IResampler { /// - public double Radius => 3; + public float Radius => 3; /// - public double GetValue(double x) + public float GetValue(float x) { if (x < 0) { @@ -24,7 +24,7 @@ namespace ImageProcessor.Samplers if (x < 3) { - return ImageMaths.SinC(x) * (1.0 - (x * x / 9.0)); + return ImageMaths.SinC(x) * (1.0f - (x * x / 9.0f)); } return 0; diff --git a/src/ImageProcessor/Samplers/Resize - Copy.cs b/src/ImageProcessor/Samplers/Resize - Copy.cs deleted file mode 100644 index d94b3753e..000000000 --- a/src/ImageProcessor/Samplers/Resize - Copy.cs +++ /dev/null @@ -1,232 +0,0 @@ -// -// Copyright (c) James South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageProcessor.Samplers -{ - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - - /// - /// Provides methods that allow the resizing of images using various resampling algorithms. - /// - public class Resize : ParallelImageProcessor - { - /// - /// The epsilon for comparing floating point numbers. - /// - private const float Epsilon = 0.0001f; - - /// - /// The horizontal weights. - /// - private Weights[] horizontalWeights; - - /// - /// The vertical weights. - /// - private Weights[] verticalWeights; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The sampler to perform the resize operation. - /// - public Resize(IResampler sampler) - { - Guard.NotNull(sampler, nameof(sampler)); - - this.Sampler = sampler; - } - - /// - /// Gets the sampler to perform the resize operation. - /// - public IResampler Sampler { get; } - - /// - protected override void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle) - { - this.horizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width); - this.verticalWeights = this.PrecomputeWeights(targetRectangle.Height, sourceRectangle.Height); - } - - /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) - { - int targetY = targetRectangle.Y; - int targetBottom = targetRectangle.Bottom; - int startX = targetRectangle.X; - int endX = targetRectangle.Right; - - Parallel.For( - startY, - endY, - y => - { - if (y >= targetY && y < targetBottom) - { - List verticalValues = this.verticalWeights[y].Values; - double verticalSum = this.verticalWeights[y].Sum; - - for (int x = startX; x < endX; x++) - { - List horizontalValues = this.horizontalWeights[x].Values; - double horizontalSum = this.horizontalWeights[x].Sum; - - // Destination color components - double r = 0; - double g = 0; - double b = 0; - double a = 0; - - foreach (Weight yw in verticalValues) - { - if (Math.Abs(yw.Value) < Epsilon) - { - continue; - } - - int originY = yw.Index; - - foreach (Weight xw in horizontalValues) - { - if (Math.Abs(xw.Value) < Epsilon) - { - continue; - } - - int originX = xw.Index; - Bgra sourceColor = source[originX, originY]; - //ColorVector sourceColor = PixelOperations.ToLinear(source[originX, originY]); - - r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - b += sourceColor.B * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - a += sourceColor.A * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - } - } - - // TODO: Double cast. - Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte()); - //Bgra destinationColor = PixelOperations.ToSrgb(new ColorVector(b, g, r, a)); - target[x, y] = destinationColor; - } - } - }); - } - - /// - /// Computes the weights to apply at each pixel when resizing. - /// - /// The destination section size. - /// The source section size. - /// - /// The . - /// - private Weights[] PrecomputeWeights(int destinationSize, int sourceSize) - { - IResampler sampler = this.Sampler; - double du = sourceSize / (double)destinationSize; - double scale = du; - - if (scale < 1) - { - scale = 1; - } - - double ru = Math.Ceiling(scale * sampler.Radius); - Weights[] result = new Weights[destinationSize]; - - for (int i = 0; i < destinationSize; i++) - { - double fu = ((i + .5) * du) - 0.5; - int startU = (int)Math.Ceiling(fu - ru); - - if (startU < 0) - { - startU = 0; - } - - int endU = (int)Math.Floor(fu + ru); - - if (endU > sourceSize - 1) - { - endU = sourceSize - 1; - } - - double sum = 0; - result[i] = new Weights(); - - for (int a = startU; a <= endU; a++) - { - double w = 255 * sampler.GetValue((a - fu) / scale); - - if (Math.Abs(w) > Epsilon) - { - sum += w; - result[i].Values.Add(new Weight(a, w)); - } - } - - result[i].Sum = sum; - } - - return result; - } - - /// - /// Represents the weight to be added to a scaled pixel. - /// - protected struct Weight - { - /// - /// The pixel index. - /// - public readonly int Index; - - /// - /// The result of the interpolation algorithm. - /// - public readonly double Value; - - /// - /// Initializes a new instance of the struct. - /// - /// The index. - /// The value. - public Weight(int index, double value) - { - this.Index = index; - this.Value = value; - } - } - - /// - /// Represents a collection of weights and their sum. - /// - protected class Weights - { - /// - /// Initializes a new instance of the class. - /// - public Weights() - { - this.Values = new List(); - } - - /// - /// Gets or sets the values. - /// - public List Values { get; set; } - - /// - /// Gets or sets the sum. - /// - public double Sum { get; set; } - } - } -} diff --git a/src/ImageProcessor/Samplers/Resize.cs b/src/ImageProcessor/Samplers/Resize.cs index 057aedf83..9b796129d 100644 --- a/src/ImageProcessor/Samplers/Resize.cs +++ b/src/ImageProcessor/Samplers/Resize.cs @@ -62,7 +62,6 @@ namespace ImageProcessor.Samplers int targetBottom = targetRectangle.Bottom; int startX = targetRectangle.X; int endX = targetRectangle.Right; - //Vector endVX = new Vector(targetRectangle.Right); Parallel.For( startY, @@ -72,18 +71,15 @@ namespace ImageProcessor.Samplers if (y >= targetY && y < targetBottom) { List verticalValues = this.verticalWeights[y].Values; - double verticalSum = this.verticalWeights[y].Sum; + float verticalSum = this.verticalWeights[y].Sum; for (int x = startX; x < endX; x++) { List horizontalValues = this.horizontalWeights[x].Values; - double horizontalSum = this.horizontalWeights[x].Sum; + float horizontalSum = this.horizontalWeights[x].Sum; // Destination color components - double r = 0; - double g = 0; - double b = 0; - double a = 0; + Color destination = new Color(0, 0, 0, 0); foreach (Weight yw in verticalValues) { @@ -102,19 +98,20 @@ namespace ImageProcessor.Samplers } int originX = xw.Index; - ColorVector sourceColor = source[originX, originY]; - //sourceColor = PixelOperations.ToLinear(sourceColor); + Color sourceColor = source[originX, originY]; + sourceColor = PixelOperations.ToLinear(sourceColor); - r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - b += sourceColor.B * (yw.Value / verticalSum) * (xw.Value / horizontalSum); - a += sourceColor.A * (yw.Value / verticalSum) * (xw.Value / horizontalSum); + float weight = (yw.Value / verticalSum) * (xw.Value / horizontalSum); + + destination.R += sourceColor.R * weight; + destination.G += sourceColor.G * weight; + destination.B += sourceColor.B * weight; + destination.A += sourceColor.A * weight; } } - // TODO: Double cast? - Bgra destinationColor = new ColorVector(b, g, r, a);//PixelOperations.ToSrgb(new ColorVector(b, g, r, a)); - target[x, y] = destinationColor; + destination = PixelOperations.ToSrgb(destination); + target[x, y] = destination; } } }); @@ -131,15 +128,15 @@ namespace ImageProcessor.Samplers private Weights[] PrecomputeWeights(int destinationSize, int sourceSize) { IResampler sampler = this.Sampler; - double du = sourceSize / (double)destinationSize; - double scale = du; + float du = sourceSize / (float)destinationSize; + float scale = du; if (scale < 1) { scale = 1; } - double ru = Math.Ceiling(scale * sampler.Radius); + float ru = (float)Math.Ceiling(scale * sampler.Radius); Weights[] result = new Weights[destinationSize]; Parallel.For( @@ -147,7 +144,7 @@ namespace ImageProcessor.Samplers destinationSize, i => { - double fu = ((i + .5) * du) - 0.5; + float fu = ((i + .5f) * du) - 0.5f; int startU = (int)Math.Ceiling(fu - ru); if (startU < 0) @@ -162,12 +159,13 @@ namespace ImageProcessor.Samplers endU = sourceSize - 1; } - double sum = 0; + float sum = 0; result[i] = new Weights(); for (int a = startU; a <= endU; a++) { - double w = 255 * sampler.GetValue((a - fu) / scale); + // TODO: CHeck multiplier here + float w = 255f * sampler.GetValue((a - fu) / scale); if (Math.Abs(w) > Epsilon) { @@ -195,14 +193,14 @@ namespace ImageProcessor.Samplers /// /// The result of the interpolation algorithm. /// - public readonly double Value; + public readonly float Value; /// /// Initializes a new instance of the struct. /// /// The index. /// The value. - public Weight(int index, double value) + public Weight(int index, float value) { this.Index = index; this.Value = value; @@ -230,7 +228,7 @@ namespace ImageProcessor.Samplers /// /// Gets or sets the sum. /// - public double Sum { get; set; } + public float Sum { get; set; } } } } diff --git a/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs b/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs index 7b6de0e0d..2a822df19 100644 --- a/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs +++ b/tests/ImageProcessor.Tests/Colors/ColorConversionTests.cs @@ -21,7 +21,7 @@ namespace ImageProcessor.Tests public class ColorConversionTests { /// - /// Tests the implicit conversion from to . + /// Tests the implicit conversion from to . /// [Fact] [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", @@ -29,7 +29,7 @@ namespace ImageProcessor.Tests public void BgrToYCbCr() { // White - Bgra color = new Bgra(255, 255, 255, 255); + Bgra32 color = new Bgra32(255, 255, 255, 255); YCbCr yCbCr = color; Assert.Equal(255, yCbCr.Y); @@ -37,14 +37,14 @@ namespace ImageProcessor.Tests Assert.Equal(128, yCbCr.Cr); // Black - Bgra color2 = new Bgra(0, 0, 0, 255); + Bgra32 color2 = new Bgra32(0, 0, 0, 255); YCbCr yCbCr2 = color2; Assert.Equal(0, yCbCr2.Y); Assert.Equal(128, yCbCr2.Cb); Assert.Equal(128, yCbCr2.Cr); // Grey - Bgra color3 = new Bgra(128, 128, 128, 255); + Bgra32 color3 = new Bgra32(128, 128, 128, 255); YCbCr yCbCr3 = color3; Assert.Equal(128, yCbCr3.Y); Assert.Equal(128, yCbCr3.Cb); @@ -52,7 +52,7 @@ namespace ImageProcessor.Tests } /// - /// Tests the implicit conversion from to . + /// Tests the implicit conversion from to . /// [Fact] [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", @@ -61,7 +61,7 @@ namespace ImageProcessor.Tests { // White YCbCr yCbCr = new YCbCr(255, 128, 128); - Bgra color = yCbCr; + Bgra32 color = yCbCr; Assert.Equal(255, color.B); Assert.Equal(255, color.G); @@ -70,7 +70,7 @@ namespace ImageProcessor.Tests // Black YCbCr yCbCr2 = new YCbCr(0, 128, 128); - Bgra color2 = yCbCr2; + Bgra32 color2 = yCbCr2; Assert.Equal(0, color2.B); Assert.Equal(0, color2.G); @@ -79,7 +79,7 @@ namespace ImageProcessor.Tests // Grey YCbCr yCbCr3 = new YCbCr(128, 128, 128); - Bgra color3 = yCbCr3; + Bgra32 color3 = yCbCr3; Assert.Equal(128, color3.B); Assert.Equal(128, color3.G); @@ -88,7 +88,7 @@ namespace ImageProcessor.Tests } /// - /// Tests the implicit conversion from to . + /// Tests the implicit conversion from to . /// [Fact] [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", @@ -96,7 +96,7 @@ namespace ImageProcessor.Tests public void BgrToHsv() { // Black - Bgra b = new Bgra(0, 0, 0, 255); + Bgra32 b = new Bgra32(0, 0, 0, 255); Hsv h = b; Assert.Equal(0, h.H); @@ -104,7 +104,7 @@ namespace ImageProcessor.Tests Assert.Equal(0, h.V); // White - Bgra color = new Bgra(255, 255, 255, 255); + Bgra32 color = new Bgra32(255, 255, 255, 255); Hsv hsv = color; Assert.Equal(0, hsv.H); @@ -112,7 +112,7 @@ namespace ImageProcessor.Tests Assert.Equal(100, hsv.V); // Dark moderate pink. - Bgra color2 = new Bgra(106, 64, 128, 255); + Bgra32 color2 = new Bgra32(106, 64, 128, 255); Hsv hsv2 = color2; Assert.Equal(320.6, hsv2.H, 1); @@ -120,7 +120,7 @@ namespace ImageProcessor.Tests Assert.Equal(50.2, hsv2.V, 1); // Ochre. - Bgra color3 = new Bgra(34, 119, 204, 255); + Bgra32 color3 = new Bgra32(34, 119, 204, 255); Hsv hsv3 = color3; Assert.Equal(30, hsv3.H, 1); @@ -129,22 +129,22 @@ namespace ImageProcessor.Tests } /// - /// Tests the implicit conversion from to . + /// Tests the implicit conversion from to . /// [Fact] public void HsvToBgr() { // Dark moderate pink. Hsv hsv = new Hsv(320.6f, 50, 50.2f); - Bgra bgra = hsv; + Bgra32 bgra32 = hsv; - Assert.Equal(bgra.B, 106); - Assert.Equal(bgra.G, 64); - Assert.Equal(bgra.R, 128); + Assert.Equal(bgra32.B, 106); + Assert.Equal(bgra32.G, 64); + Assert.Equal(bgra32.R, 128); // Ochre Hsv hsv2 = new Hsv(30, 83.3f, 80); - Bgra bgra2 = hsv2; + Bgra32 bgra2 = hsv2; Assert.Equal(bgra2.B, 34); Assert.Equal(bgra2.G, 119); @@ -152,7 +152,7 @@ namespace ImageProcessor.Tests // White Hsv hsv3 = new Hsv(0, 0, 100); - Bgra bgra3 = hsv3; + Bgra32 bgra3 = hsv3; Assert.Equal(bgra3.B, 255); Assert.Equal(bgra3.G, 255); @@ -162,14 +162,14 @@ namespace ImageProcessor.Tests Random random = new Random(0); for (int i = 0; i < 1000; i++) { - Bgra bgra4 = new Bgra((byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255)); + Bgra32 bgra4 = new Bgra32((byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255)); Hsv hsb4 = bgra4; - Assert.Equal(bgra4, (Bgra)hsb4); + Assert.Equal(bgra4, (Bgra32)hsb4); } } /// - /// Tests the implicit conversion from to . + /// Tests the implicit conversion from to . /// [Fact] [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", @@ -177,7 +177,7 @@ namespace ImageProcessor.Tests public void BgrToCmyk() { // White - Bgra color = new Bgra(255, 255, 255, 255); + Bgra32 color = new Bgra32(255, 255, 255, 255); Cmyk cmyk = color; Assert.Equal(0, cmyk.C); @@ -186,7 +186,7 @@ namespace ImageProcessor.Tests Assert.Equal(0, cmyk.K); // Black - Bgra color2 = new Bgra(0, 0, 0, 255); + Bgra32 color2 = new Bgra32(0, 0, 0, 255); Cmyk cmyk2 = color2; Assert.Equal(0, cmyk2.C); Assert.Equal(0, cmyk2.M); @@ -194,7 +194,7 @@ namespace ImageProcessor.Tests Assert.Equal(100, cmyk2.K); // Grey - Bgra color3 = new Bgra(128, 128, 128, 255); + Bgra32 color3 = new Bgra32(128, 128, 128, 255); Cmyk cmyk3 = color3; Assert.Equal(0, cmyk3.C); Assert.Equal(0, cmyk3.M); @@ -202,7 +202,7 @@ namespace ImageProcessor.Tests Assert.Equal(49.8, cmyk3.K, 1); // Checked with other tools. // Cyan - Bgra color4 = new Bgra(255, 255, 0, 255); + Bgra32 color4 = new Bgra32(255, 255, 0, 255); Cmyk cmyk4 = color4; Assert.Equal(100, cmyk4.C); Assert.Equal(0, cmyk4.M); @@ -211,22 +211,22 @@ namespace ImageProcessor.Tests } /// - /// Tests the implicit conversion from to . + /// Tests the implicit conversion from to . /// [Fact] public void CmykToBgr() { // Dark moderate pink. Cmyk cmyk = new Cmyk(49.8f, 74.9f, 58.4f, 0); - Bgra bgra = cmyk; + Bgra32 bgra32 = cmyk; - Assert.Equal(bgra.B, 106); - Assert.Equal(bgra.G, 64); - Assert.Equal(bgra.R, 128); + Assert.Equal(bgra32.B, 106); + Assert.Equal(bgra32.G, 64); + Assert.Equal(bgra32.R, 128); // Ochre Cmyk cmyk2 = new Cmyk(20, 53.3f, 86.7f, 0); - Bgra bgra2 = cmyk2; + Bgra32 bgra2 = cmyk2; Assert.Equal(bgra2.B, 34); Assert.Equal(bgra2.G, 119); @@ -234,7 +234,7 @@ namespace ImageProcessor.Tests // White Cmyk cmyk3 = new Cmyk(0, 0, 0, 0); - Bgra bgra3 = cmyk3; + Bgra32 bgra3 = cmyk3; Assert.Equal(bgra3.B, 255); Assert.Equal(bgra3.G, 255); @@ -244,9 +244,9 @@ namespace ImageProcessor.Tests Random random = new Random(0); for (int i = 0; i < 1000; i++) { - Bgra bgra4 = new Bgra((byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255)); + Bgra32 bgra4 = new Bgra32((byte)random.Next(255), (byte)random.Next(255), (byte)random.Next(255)); Cmyk cmyk4 = bgra4; - Assert.Equal(bgra4, (Bgra)cmyk4); + Assert.Equal(bgra4, (Bgra32)cmyk4); } } } diff --git a/tests/ImageProcessor.Tests/Colors/ColorTests.cs b/tests/ImageProcessor.Tests/Colors/ColorTests.cs index 0f592e349..626cb14d0 100644 --- a/tests/ImageProcessor.Tests/Colors/ColorTests.cs +++ b/tests/ImageProcessor.Tests/Colors/ColorTests.cs @@ -13,7 +13,7 @@ namespace ImageProcessor.Tests using Xunit; /// - /// Tests the struct. + /// Tests the struct. /// public class ColorTests { @@ -23,12 +23,12 @@ namespace ImageProcessor.Tests [Fact] public void AreEqual() { - Bgra color1 = new Bgra(0, 0, 0, 255); - Bgra color2 = new Bgra(0, 0, 0, 255); - Bgra color3 = new Bgra("#000"); - Bgra color4 = new Bgra("#000000"); - Bgra color5 = new Bgra("#FF000000"); - Bgra color6 = new Bgra(-16777216); + Bgra32 color1 = new Bgra32(0, 0, 0, 255); + Bgra32 color2 = new Bgra32(0, 0, 0, 255); + Bgra32 color3 = new Bgra32("#000"); + Bgra32 color4 = new Bgra32("#000000"); + Bgra32 color5 = new Bgra32("#FF000000"); + Bgra32 color6 = new Bgra32(-16777216); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -43,12 +43,12 @@ namespace ImageProcessor.Tests [Fact] public void AreNotEqual() { - Bgra color1 = new Bgra(255, 0, 0, 255); - Bgra color2 = new Bgra(0, 0, 0, 255); - Bgra color3 = new Bgra("#000"); - Bgra color4 = new Bgra("#000000"); - Bgra color5 = new Bgra("#FF000000"); - Bgra color6 = new Bgra(-16777216); + Bgra32 color1 = new Bgra32(255, 0, 0, 255); + Bgra32 color2 = new Bgra32(0, 0, 0, 255); + Bgra32 color3 = new Bgra32("#000"); + Bgra32 color4 = new Bgra32("#000000"); + Bgra32 color5 = new Bgra32("#FF000000"); + Bgra32 color6 = new Bgra32(-16777216); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -63,25 +63,25 @@ namespace ImageProcessor.Tests [Fact] public void ConstructorAssignsProperties() { - Bgra color1 = new Bgra(255, 10, 34, 220); + Bgra32 color1 = new Bgra32(255, 10, 34, 220); Assert.Equal(255, color1.B); Assert.Equal(10, color1.G); Assert.Equal(34, color1.R); Assert.Equal(220, color1.A); - Bgra color2 = new Bgra(255, 10, 34); + Bgra32 color2 = new Bgra32(255, 10, 34); Assert.Equal(255, color2.B); Assert.Equal(10, color2.G); Assert.Equal(34, color2.R); Assert.Equal(255, color2.A); - Bgra color3 = new Bgra(-1); + Bgra32 color3 = new Bgra32(-1); Assert.Equal(255, color3.B); Assert.Equal(255, color3.G); Assert.Equal(255, color3.R); Assert.Equal(255, color3.A); - Bgra color4 = new Bgra("#FF0000"); + Bgra32 color4 = new Bgra32("#FF0000"); Assert.Equal(0, color4.B); Assert.Equal(0, color4.G); Assert.Equal(255, color4.R); @@ -95,7 +95,7 @@ namespace ImageProcessor.Tests public void ConvertHex() { const string First = "FF000000"; - string second = new Bgra(0, 0, 0, 255).BGRA.ToString("X"); + string second = new Bgra32(0, 0, 0, 255).BGRA.ToString("X"); Assert.Equal(First, second); } } diff --git a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs index cb22fe8db..e2023a2c3 100644 --- a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs +++ b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs @@ -21,8 +21,8 @@ namespace ImageProcessor.Tests { "../../TestImages/Formats/Jpg/Backdrop.jpg", //"../../TestImages/Formats/Jpg/Calliphora.jpg", - //"../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg", - //"../../TestImages/Formats/Jpg/greyscale.jpg", + "../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg", + "../../TestImages/Formats/Jpg/greyscale.jpg", //"../../TestImages/Formats/Bmp/Car.bmp", //"../../TestImages/Formats/Png/cmyk.png", //"../../TestImages/Formats/Png/gamma-1.0-or-2.2.png", diff --git a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs index cd42165c8..c566416fa 100644 --- a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs +++ b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs @@ -15,18 +15,18 @@ namespace ImageProcessor.Tests new TheoryData { { "Bicubic", new BicubicResampler() }, - { "Triangle", new TriangleResampler() }, - { "Box", new BoxResampler() }, - { "Lanczos3", new Lanczos3Resampler() }, - { "Lanczos5", new Lanczos5Resampler() }, - { "Lanczos8", new Lanczos8Resampler() }, - { "MitchellNetravali", new MitchellNetravaliResampler() }, - { "Hermite", new HermiteResampler() }, - { "Spline", new SplineResampler() }, - { "Robidoux", new RobidouxResampler() }, - { "RobidouxSharp", new RobidouxSharpResampler() }, - { "RobidouxSoft", new RobidouxSoftResampler() }, - { "Welch", new WelchResampler() } + //{ "Triangle", new TriangleResampler() }, + //{ "Box", new BoxResampler() }, + //{ "Lanczos3", new Lanczos3Resampler() }, + //{ "Lanczos5", new Lanczos5Resampler() }, + //{ "Lanczos8", new Lanczos8Resampler() }, + //{ "MitchellNetravali", new MitchellNetravaliResampler() }, + //{ "Hermite", new HermiteResampler() }, + //{ "Spline", new SplineResampler() }, + //{ "Robidoux", new RobidouxResampler() }, + //{ "RobidouxSharp", new RobidouxSharpResampler() }, + //{ "RobidouxSoft", new RobidouxSoftResampler() }, + //{ "Welch", new WelchResampler() } }; [Theory] @@ -48,7 +48,7 @@ namespace ImageProcessor.Tests using (FileStream output = File.OpenWrite($"Resized/{filename}")) { //image.Resize(image.Width / 2, image.Height / 2, sampler).Save(output); - image.Resize(500, 750, sampler).Save(output); + image.Resize(image.Width / 2, image.Height / 2, sampler).Save(output); } Trace.WriteLine($"{name}: {watch.ElapsedMilliseconds}ms"); @@ -63,10 +63,10 @@ namespace ImageProcessor.Tests [InlineData(1, 0)] [InlineData(2, 0)] [InlineData(2, 0)] - public static void Lanczos3WindowOscillatesCorrectly(double x, double expected) + public static void Lanczos3WindowOscillatesCorrectly(float x, float expected) { Lanczos3Resampler sampler = new Lanczos3Resampler(); - double result = sampler.GetValue(x); + float result = sampler.GetValue(x); Assert.Equal(result, expected); } From a44eb438be9cf86e149c8926b93e644a4318c355 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 30 Oct 2015 14:14:41 +1100 Subject: [PATCH 04/15] Fix stylecop issues Former-commit-id: d901cd8d2492eff7048d62296f4f3e53e7083dd1 Former-commit-id: 224e01f61e0dcd4fecaf49112562f974b00989a0 Former-commit-id: 671034a706cdfb6d188f90d3b03018b2849a303e --- .gitignore | 1 + src/ImageProcessor/Colors/Color.cs | 5 +++++ src/ImageProcessor/Colors/Formats/Bgra32.cs | 2 +- .../Common/Helpers/PixelOperations.cs | 1 - src/ImageProcessor/ImageProcessor.csproj | 6 ++++-- src/ImageProcessor/Samplers/Resize.cs | 5 ++--- src/ImageProcessor/project.lock.json.REMOVED.git-id | 2 +- src/ImageProcessor/stylecop.json | 13 +++++++++++++ 8 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 src/ImageProcessor/stylecop.json diff --git a/.gitignore b/.gitignore index 4e9864be0..ae6765a03 100644 --- a/.gitignore +++ b/.gitignore @@ -108,6 +108,7 @@ TestResults *.Cache ClientBin stylecop.* +!stylecop.json ~$* *.dbmdl Generated_Code #added for RIA/Silverlight projects diff --git a/src/ImageProcessor/Colors/Color.cs b/src/ImageProcessor/Colors/Color.cs index 3f2d27d3b..682e5f119 100644 --- a/src/ImageProcessor/Colors/Color.cs +++ b/src/ImageProcessor/Colors/Color.cs @@ -16,6 +16,11 @@ namespace ImageProcessor /// public struct Color { + /// + /// Represents a that has R, G, B, and A values set to zero. + /// + public static readonly Color Empty = default(Color); + /// /// The backing vector for SIMD support. /// diff --git a/src/ImageProcessor/Colors/Formats/Bgra32.cs b/src/ImageProcessor/Colors/Formats/Bgra32.cs index 9fef962f4..01e2e664f 100644 --- a/src/ImageProcessor/Colors/Formats/Bgra32.cs +++ b/src/ImageProcessor/Colors/Formats/Bgra32.cs @@ -26,7 +26,7 @@ namespace ImageProcessor public static readonly Bgra32 Transparent = new Bgra32(255, 255, 255, 0); /// - /// Represents a black that has B, G, R, and A values set to 0, 0, 0, 0. + /// Represents a black that has B, G, R, and A values set to 0, 0, 0, 255. /// public static readonly Bgra32 Black = new Bgra32(0, 0, 0, 255); diff --git a/src/ImageProcessor/Common/Helpers/PixelOperations.cs b/src/ImageProcessor/Common/Helpers/PixelOperations.cs index 048b2e6b2..a116c0e35 100644 --- a/src/ImageProcessor/Common/Helpers/PixelOperations.cs +++ b/src/ImageProcessor/Common/Helpers/PixelOperations.cs @@ -6,7 +6,6 @@ namespace ImageProcessor { using System; - using System.Collections.Concurrent; /// /// Performs per-pixel operations. diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 6ada545a7..3e506f65e 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -39,6 +39,7 @@ TRACE prompt 4 + bin\Release\ImageProcessor.XML @@ -237,13 +238,14 @@ - - + + +